respond_to :html
- # omniauth callback method
- def create
- omniauth = request.env['omniauth.auth']
+ def login
+ return send_error "Legacy code path no longer supported", status: 404
+ end
- identity_url_ok = (omniauth['info']['identity_url'].length > 0) rescue false
- unless identity_url_ok
- # Whoa. This should never happen.
- logger.error "UserSessionsController.create: omniauth object missing/invalid"
- logger.error "omniauth: "+omniauth.pretty_inspect
+ def logout
+ return send_error "Legacy code path no longer supported", status: 404
+ end
- return redirect_to login_failure_url
+ # create a new session
+ def create
+ remote, return_to_url = params[:return_to].split(',', 2)
+ if params[:provider] != 'controller' ||
+ return_to_url != 'https://controller.api.client.invalid'
+ return send_error "Legacy code path no longer supported", status: 404
end
-
- # Only local users can create sessions, hence uuid_like_pattern
- # here.
- user = User.unscoped.where('identity_url = ? and uuid like ?',
- omniauth['info']['identity_url'],
- User.uuid_like_pattern).first
- if not user
- # Check for permission to log in to an existing User record with
- # a different identity_url
- Link.where("link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
- 'permission',
- 'can_login',
- omniauth['info']['email'],
- User.uuid_like_pattern).each do |link|
- if prefix = link.properties['identity_url_prefix']
- if prefix == omniauth['info']['identity_url'][0..prefix.size-1]
- user = User.find_by_uuid(link.head_uuid)
- break if user
- end
- end
- end
+ if request.headers['Authorization'] != 'Bearer ' + Rails.configuration.SystemRootToken
+ return send_error('Invalid authorization header', status: 401)
end
-
- if not user
- # New user registration
- user = User.new(:email => omniauth['info']['email'],
- :first_name => omniauth['info']['first_name'],
- :last_name => omniauth['info']['last_name'],
- :identity_url => omniauth['info']['identity_url'],
- :is_active => Rails.configuration.Users.NewUsersAreActive,
- :owner_uuid => system_user_uuid)
- if omniauth['info']['username']
- user.set_initial_username(requested: omniauth['info']['username'])
- end
- act_as_system_user do
- user.save or raise Exception.new(user.errors.messages)
+ if remote == ''
+ remote = nil
+ elsif remote !~ /^[0-9a-z]{5}$/
+ return send_error 'Invalid remote cluster id', status: 400
+ end
+ # arvados-controller verified the user and is passing auth_info
+ # in request params.
+ authinfo = SafeJSON.load(params[:auth_info])
+ max_expires_at = authinfo["expires_at"]
+
+ if !authinfo['user_uuid'].blank?
+ user = User.find_by_uuid(authinfo['user_uuid'])
+ if !user
+ Rails.logger.warn "Nonexistent user_uuid in authinfo #{authinfo.inspect}"
+ return redirect_to login_failure_url
end
else
- user.email = omniauth['info']['email']
- user.first_name = omniauth['info']['first_name']
- user.last_name = omniauth['info']['last_name']
- if user.identity_url.nil?
- # First login to a pre-activated account
- user.identity_url = omniauth['info']['identity_url']
- end
-
- while (uuid = user.redirect_to_user_uuid)
- user = User.unscoped.where(uuid: uuid).first
- if !user
- raise Exception.new("identity_url #{omniauth['info']['identity_url']} redirects to nonexistent uuid #{uuid}")
- end
+ begin
+ user = User.register(authinfo)
+ rescue => e
+ Rails.logger.warn "User.register error #{e}"
+ Rails.logger.warn "authinfo was #{authinfo.inspect}"
+ return redirect_to login_failure_url
end
end
# For the benefit of functional and integration tests:
@user = user
- if user.uuid[0..4] != Rails.configuration.ClusterID
- # Actually a remote user
- # Send them to their home cluster's login
- rh = Rails.configuration.RemoteClusters[user.uuid[0..4]]
- remote, return_to_url = params[:return_to].split(',', 2)
- @remotehomeurl = "#{rh.Scheme || "https"}://#{rh.Host}/login?remote=#{Rails.configuration.ClusterID}&return_to=#{return_to_url}"
- render
- return
- end
-
# prevent ArvadosModel#before_create and _update from throwing
# "unauthorized":
Thread.current[:user] = user
user.save or raise Exception.new(user.errors.messages)
- omniauth.delete('extra')
-
- # Give the authenticated user a cookie for direct API access
- session[:user_id] = user.id
- session[:api_client_uuid] = nil
- session[:api_client_trusted] = true # full permission to see user's secrets
-
- @redirect_to = root_path
- if params.has_key?(:return_to)
- # return_to param's format is 'remote,return_to_url'. This comes from login()
- # encoding the remote=zbbbb parameter passed by a client asking for a salted
- # token.
- remote, return_to_url = params[:return_to].split(',', 2)
- if remote !~ /^[0-9a-z]{5}$/ && remote != ""
- return send_error 'Invalid remote cluster id', status: 400
- end
- remote = nil if remote == ''
- return send_api_token_to(return_to_url, user, remote)
- end
- redirect_to @redirect_to
+ return send_api_token_to(return_to_url, user, remote, max_expires_at)
end
# Omniauth failure callback
flash[:notice] = params[:message]
end
- # logout - Clear our rack session BUT essentially redirect to the provider
- # to clean up the Devise session from there too !
- def logout
- session[:user_id] = nil
-
- flash[:notice] = 'You have logged off'
- return_to = params[:return_to] || root_url
- redirect_to "#{Rails.configuration.Services.SSO.ExternalURL}/users/sign_out?redirect_uri=#{CGI.escape return_to}"
- end
-
- # login - Just bounce to /auth/joshid. The only purpose of this function is
- # to save the return_to parameter (if it exists; see the application
- # controller). /auth/joshid bypasses the application controller.
- def login
- if params[:remote] !~ /^[0-9a-z]{5}$/ && !params[:remote].nil?
- return send_error 'Invalid remote cluster id', status: 400
- end
- if current_user and params[:return_to]
- # Already logged in; just need to send a token to the requesting
- # API client.
- #
- # FIXME: if current_user has never authorized this app before,
- # ask for confirmation here!
-
- return send_api_token_to(params[:return_to], current_user, params[:remote])
- end
- p = []
- p << "auth_provider=#{CGI.escape(params[:auth_provider])}" if params[:auth_provider]
-
- login_cluster = ""
- if !Rails.configuration.Login.LoginCluster.empty?
- cluster = Rails.configuration.RemoteClusters[Rails.configuration.Login.LoginCluster]
- scheme = "https"
- if cluster['Scheme'] and !cluster['Scheme'].empty?
- scheme = cluster['Scheme']
- end
- login_cluster = "#{scheme}://#{cluster['Host']}"
- p << "remote=#{CGI.escape(params[:remote])}" if params[:remote]
- p << "return_to=#{CGI.escape(params[:return_to])}" if params[:return_to]
- redirect_to "#{login_cluster}/login?#{p.join('&')}"
- else
- if params[:return_to]
- # Encode remote param inside callback's return_to, so that we'll get it on
- # create() after login.
- remote_param = params[:remote].nil? ? '' : params[:remote]
- p << "return_to=#{CGI.escape(remote_param + ',' + params[:return_to])}"
- end
- redirect_to "/auth/joshid?#{p.join('&')}"
- end
- end
-
- def send_api_token_to(callback_url, user, remote=nil)
+ def send_api_token_to(callback_url, user, remote=nil, token_expiration=nil)
# Give the API client a token for making API calls on behalf of
# the authenticated user
@api_client = ApiClient.
find_or_create_by(url_prefix: api_client_url_prefix)
end
+ if Rails.configuration.Login.TokenLifetime > 0
+ if token_expiration == nil
+ token_expiration = db_current_time + Rails.configuration.Login.TokenLifetime
+ else
+ token_expiration = [token_expiration, db_current_time + Rails.configuration.Login.TokenLifetime].min
+ end
+ end
@api_client_auth = ApiClientAuthorization.
new(user: user,
api_client: @api_client,
created_by_ip_address: remote_ip,
+ expires_at: token_expiration,
scopes: ["all"])
@api_client_auth.save!
token = @api_client_auth.salted_token(remote: remote)
end
callback_url += 'api_token=' + token
- redirect_to callback_url
+ redirect_to callback_url, allow_other_host: true
end
def cross_origin_forbidden