Skip to content

Commit

Permalink
Getting an extra cas ticket that we could theoretically pass along to…
Browse files Browse the repository at this point in the history
… mediaflux (#875)

* Getting an extra cas ticket that we could theoreticall pass along to mediaflux

* Allow UI to load eve if mediaflux is down

* Pass along the ticket to mediaflux to login

Also updgrade mediaflux to 4.16.082

* debug soo many logins

* Removing mediaflux from health monitor
It logs in every second and then asks for the version.  Research Computing wishes it would login less

* Adding the concept of a System Login and an Active Web Login
  • Loading branch information
carolyncole authored Dec 16, 2024
1 parent 11683cc commit 92be0d2
Show file tree
Hide file tree
Showing 71 changed files with 348 additions and 119 deletions.
6 changes: 1 addition & 5 deletions app/channels/mediaflux_channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@ def update_state

private

def superuser
User.find_by(superuser: true)
end

def session_token
superuser.mediaflux_session
SystemUser.mediaflux_session
end

def version_request
Expand Down
40 changes: 36 additions & 4 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
around_action :mediaflux_session
before_action :mediaflux_session
around_action :mediaflux_session_errors
around_action :mediaflux_login_errors
before_action :emulate_user

helper_method :breadcrumbs
Expand All @@ -11,6 +13,11 @@ def new_session_path(_scope)
new_user_session_path
end

def after_sign_in_path_for(_resource)
mediaflux_passthru_path
# "/users/#{@user.id}"
end

def require_admin_user
head :forbidden unless current_user&.eligible_sysadmin?
end
Expand All @@ -26,12 +33,37 @@ def add_breadcrumb(name, path = nil)
private

def mediaflux_session
# this requires a connection to mediaflux... for ease of development we do not want to require this
# current_user&.mediaflux_from_session(session)
logger.debug "Application Session #{session[:mediaflux_session]} cas: #{session[:active_web_user]}"
unless ["passthru", "cas"].include?(action_name)
current_user&.mediaflux_from_session(session)
end
end

def mediaflux_session_errors
yield
rescue Mediaflux::SessionExpired
rescue ActionView::Template::Error, Mediaflux::SessionExpired => e
raise unless e.is_a?(Mediaflux::SessionExpired) || e.cause.is_a?(Mediaflux::SessionExpired)
if session[:active_web_user]
redirect_to mediaflux_passthru_path(path: request.path)
else
@retry_count ||= 0
@retry_count += 1

current_user.mediaflux_from_session(session)
if @retry_count < 3 # If the session is expired we should not have to retry more than once, but let's have a little wiggle room
retry
else
raise
end
end
end

def mediaflux_login_errors
yield
rescue Mediaflux::SessionError
@retry_count ||= 0
@retry_count += 1

current_user.clear_mediaflux_session(session)
current_user.mediaflux_from_session(session)
if @retry_count < 3 # If the session is expired we should not have to retry more than once, but let's have a little wiggle room
Expand Down
15 changes: 15 additions & 0 deletions app/controllers/users/mediaflux_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true
class Users::MediafluxCallbacksController < ApplicationController
def passthru
session[:original_path] = params["path"]
redirect_to session[:cas_login_url], allow_other_host: true
end

def cas
ticket = params[:ticket]
uri = URI.parse(session[:cas_validation_url])
token = "#{uri.query}#{ticket}"
current_user.medaiflux_login(token, session)
redirect_to(session["original_path"] || root_path)
end
end
13 changes: 13 additions & 0 deletions app/controllers/users/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ def cas
access_token = request.env["omniauth.auth"]
@user = User.from_cas(access_token)

set_cas_session

if @user.nil? && access_token&.provider == "cas"
redirect_to help_path
flash.notice = "You can not be signed in at this time."
Expand All @@ -14,4 +16,15 @@ def cas
sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
end
end

private

def set_cas_session
strategy = request.env["omniauth.strategy"]
if strategy.present?
service_url = strategy.append_params(mediaflux_extra_url, { url: request.referer })
session[:cas_login_url] = strategy.login_url(service_url)
session[:cas_validation_url] = strategy.service_validate_url(service_url, "")
end
end
end
6 changes: 0 additions & 6 deletions app/jobs/activate_project_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,4 @@ def perform(user:, project_id:)
}
Honeybadger.notify(activation_failure_msg, context: honeybadger_context)
end

private
def mediaflux_session
logon_request = Mediaflux::LogonRequest.new
logon_request.session_token
end
end
8 changes: 6 additions & 2 deletions app/models/mediaflux/logon_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ def self.mediaflux_password
mediaflux["api_password"]
end

def initialize(domain: self.class.mediaflux_domain, user: self.class.mediaflux_user, password: self.class.mediaflux_password, identity_token: nil)
def initialize(domain: self.class.mediaflux_domain, user: self.class.mediaflux_user, password: self.class.mediaflux_password, identity_token: nil, token_type: nil)
@domain = domain
@user = user
@password = password
@identity_token = identity_token
@token_type = token_type
super()
end

Expand Down Expand Up @@ -67,7 +68,10 @@ def build_http_request_body(name:)
xml.user @user
xml.password @password
else
xml.token @identity_token
xml.token do
xml.parent.set_attribute("type", @token_type) if @token_type
xml.text(@identity_token)
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/mediaflux/project_approve_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ module Mediaflux
#
# @example
# project = Project.first
# project.save_in_mediaflux(session_id: User.first.mediaflux_session)
# approve_req = Mediaflux::ProjectApproveRequest.new(session_token: User.first.mediaflux_session, project:)
# project.save_in_mediaflux(session_id: SystemUser.mediaflux_session)
# approve_req = Mediaflux::ProjectApproveRequest.new(session_token: SystemUser.mediaflux_session, project:)
# approve_req.resolve
#
class ProjectApproveRequest < Request
Expand Down
8 changes: 8 additions & 0 deletions app/models/mediaflux/session_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true
module Mediaflux
# A error to be thrown when the session logon has an error
# This error should not happen, but can happen if there is a bad password or a communication error
#
class SessionError < StandardError
end
end
12 changes: 12 additions & 0 deletions app/models/system_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true
class SystemUser
def self.mediaflux_session
Rails.cache.fetch("mediaflux_session", expires_in: 10.minutes) do
logon_request = Mediaflux::LogonRequest.new
if logon_request.error?
raise Mediaflux::SessionError, "System logon was invalid! #{logon_request.response_error}"
end
logon_request.session_token
end
end
end
29 changes: 21 additions & 8 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class User < ApplicationRecord

USER_REGISTRATION_LIST = Rails.root.join("data", "user_registration_list_#{Rails.env}.csv")

attr_accessor :mediaflux_session

def self.from_cas(access_token)
user = User.find_by(provider: access_token.provider, uid: access_token.uid)
if user.present? && user.given_name.nil? # fix any users that do not have the name information loaded
Expand Down Expand Up @@ -38,27 +40,38 @@ def self.manager_users
end

def clear_mediaflux_session(session)
Rails.logger.debug("!!!!!!! Clearing Mediaflux session !!!!!!!!")
@mediaflux_session = nil
session[:mediaflux_session] = nil
end

def mediaflux_from_session(session)
logger.debug "Session Get #{session[:mediaflux_session]} cas: #{session[:active_web_user]} user: #{uid}"
if session[:mediaflux_session].blank?
session[:mediaflux_session] = mediaflux_session
else
@mediaflux_session = session[:mediaflux_session]
logger.debug("!!!! Creating a new session !!! #{uid}")
session[:mediaflux_session] = SystemUser.mediaflux_session
session[:active_web_user] = false
end
@active_web_user = session[:active_web_user]
@mediaflux_session = session[:mediaflux_session]
end

def mediaflux_session
@mediaflux_session ||= begin
logon_request = Mediaflux::LogonRequest.new
logon_request.session_token
end
def medaiflux_login(token, session)
logger.debug("mediaflux session created for #{uid}")
logon_request = Mediaflux::LogonRequest.new(identity_token: token, token_type: "cas")
if logon_request.error?
raise "Invalid Logon #{logon_request.response_error}"
end
@mediaflux_session = logon_request.session_token
@active_web_user = true
session[:mediaflux_session] = @mediaflux_session
session[:active_web_user] = @active_web_user
logger.debug "Login Session #{session[:mediaflux_session]} cas: #{session[:active_web_user]} user: #{uid}"
end

def terminate_mediaflux_session
return if @mediaflux_session.nil? # nothing to terminate
logger.debug "!!!! Terminating mediaflux session"

Mediaflux::LogoutRequest.new(session_token: @mediaflux_session).response_body
@mediaflux_session = nil
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<div class="row">
<div class="col">
<% if flash[:notice]%>
<div class="alert alert-primary" role="alert" ><%= flash[:notice] %></div>
<div class="alert alert-primary" role="alert" ><%= flash[:notice]&.html_safe %></div>
<% end %>
<% if flash[:alert]%>
<div class="alert alert-warning" role="alert"><%= flash[:alert] %></div>
Expand Down
2 changes: 1 addition & 1 deletion config/environments/qa.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).
config.log_level = :info
config.log_level = :debug

# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
Expand Down
3 changes: 3 additions & 0 deletions config/initializers/health_monitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
# Mediaflux check
config.add_custom_provider(MediafluxStatus)

# allow the UI to load evn if mediaflux is down
config.providers.last.configuration.critical = false

# Make this health check available at /health
config.path = :health

Expand Down
2 changes: 1 addition & 1 deletion config/mediaflux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ development:
api_transport: <%= ENV["MEDIAFLUX_TRANSPORT"] || 'http' %>
api_host: <%= ENV["MEDIAFLUX_HOST"] || '0.0.0.0' %>
api_port: <%= ENV["MEDIAFLUX_PORT"] || '8888' %>

# Alternate to development is an alternate location in docker
api_alternate_hidden_root: '/td-alternate-001'
api_alternate_root_ns: '/td-alternate-001/tigerdataNS'
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@
end

mount ActionCable.server => "/cable"
get "mediaflux_extra", to: "users/mediaflux_callbacks#cas", as: :mediaflux_extra
get "mediaflux_passthru", to: "users/mediaflux_callbacks#passthru", as: :mediaflux_passthru
end
2 changes: 1 addition & 1 deletion docs/aterm_101.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ For example:

**Note 2** Our version of mediaflux in docker does not have this command. The xtoshell command does exist on td-meta1
```
session_id = User.first.mediaflux_session
session_id = SystemUser.mediaflux_session
project = Project.first
project_name = project.project_directory
project_namespace = "#{project_name}NS"
Expand Down
4 changes: 2 additions & 2 deletions docs/local_development.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ You can also utilize the TestAssetGenerator in the rails console to add assets t
rails c
user = User.first
project = Project.last
project.save_in_mediaflux(session_id: user.mediaflux_session)
project.save_in_mediaflux(session_id: SystemUser.mediaflux_session)
gen = TestAssetGenerator.new(project_id: project.id,user:, levels: 2, directory_per_level: 2,file_count_per_directory: 20)
gen.generate
```
Expand All @@ -137,7 +137,7 @@ You can also utilize `Mediaflux::TestAssetCreateRequest` to generate some assets
```
rails c
parent_id = 1234 # collection id from mediaflux
gen = Mediaflux::TestAssetCreateRequest.new(session_token: User.first.mediaflux_session, parent_id:, count: 5, pattern: "test_asset_" )
gen = Mediaflux::TestAssetCreateRequest.new(session_token: SystemUser.mediaflux_session, parent_id:, count: 5, pattern: "test_asset_" )
gen.resolve
```

Expand Down
2 changes: 1 addition & 1 deletion docs/mediaflux_manual_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Per notes from Robert Knight, Mediaflux production is running Java 1.8.0.412.b08
### 4. get the installer
```unix
$ sudo dnf install wget
$ wget https://www.arcitecta.com/software/mf/4.16.071/mflux-dev_4.16.071_jvm_1.8.jar
$ wget https://www.arcitecta.com/software/mf/4.16.082/mflux-dev_4.16.082_jvm_1.8.jar
$ sudo java -jar mflux-dev_jvm_1.8.jar nogui
-> accept
-> /opt/mediaflux
Expand Down
2 changes: 1 addition & 1 deletion docs/mediaflux_script_access.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Because the user has has access to `server.log` we can even look at the log on t
$ cat /usr/local/mediaflux/volatile/logs/filelist.1.log
# output will include something along the lines of
# [281 76649: Network Connection: http [port=8888]],version=4.16.071,filelist,30-Sep-2024
# [281 76649: Network Connection: http [port=8888]],version=4.16.082,filelist,30-Sep-2024
# 20:34:44.081:INFO:[user, id=157] system:scripter_user: File list for /path/to/collection
```

Expand Down
1 change: 1 addition & 0 deletions lib/tasks/projects.rake
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace :projects do
raise "User id must be specified" if uid.blank?
user = User.find_by(uid:)
raise "User #{uid} not found" if user.nil?
user.mediaflux_from_session({}) # make sure we have the system login
project_prefix = args[:prefix]
raise "Project prefix must be specified" if project_prefix.nil?
number = rand(10_000)
Expand Down
2 changes: 1 addition & 1 deletion spec/channels/mediaflux_channel_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
identifier
]
end
let(:superuser) { FactoryBot.create(:superuser) }
let(:superuser) { FactoryBot.create(:superuser, mediaflux_session: SystemUser.mediaflux_session) }

before do
superuser
Expand Down
6 changes: 3 additions & 3 deletions spec/controllers/mediaflux_info_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
require "rails_helper"

RSpec.describe MediafluxInfoController, connect_to_mediaflux: true do
let(:user) { FactoryBot.create :user }
let(:user) { FactoryBot.create :user, mediaflux_session: SystemUser.mediaflux_session }
let(:docker_response) { "{\"vendor\":\"Arcitecta Pty. Ltd.\",\"version\":\"4.16.071\"}" }
let(:ansible_response) { "{\"vendor\":\"Arcitecta Pty. Ltd.\",\"version\":\"4.16.047\"}" }
let(:ansible_response) { "{\"vendor\":\"Arcitecta Pty. Ltd.\",\"version\":\"4.16.082\"}" }

before do
sign_in user
Expand All @@ -24,7 +24,7 @@

Rails.configuration.mediaflux["api_password"] = "badpass"

expect { get :index }.to raise_error(Mediaflux::SessionExpired)
expect { get :index }.to raise_error(Mediaflux::SessionError)

Rails.configuration.mediaflux["api_password"] = original_pass
end
Expand Down
2 changes: 1 addition & 1 deletion spec/controllers/omniauth_callbacks_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
it "redirects to home page with notice" do
allow(User).to receive(:from_cas) { project_sponsor }
get :cas
expect(response).to redirect_to(root_path)
expect(response).to redirect_to(mediaflux_passthru_path)
end
end

Expand Down
Loading

0 comments on commit 92be0d2

Please sign in to comment.