From ef3985b22cbc5b0185d83ca10b7ec8663e6fb65b Mon Sep 17 00:00:00 2001 From: hellekin Date: Tue, 6 Oct 2020 15:11:37 +0200 Subject: Refactor authentication method to make it a bit more readable --- app/controllers/welcome_controller.rb | 102 ++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 0ca7af4..5e80d26 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -6,60 +6,42 @@ class WelcomeController < ApplicationController # GET /authenticate(/:token) # Discourse SSO Authentication def authenticate - # Ensure nobody tries silly things with our session - if params[:token].present? && !params[:token].match?(/[a-z0-9]{32}/) - raise(ArgumentError, "Token invalid") - end + validate_token_format! # Try an ongoing SSO or create a new one @sso = SSO::FromDiscourse.new(token: params[:token], nonce: session[params[:token]]) - # Remove any current session - Rails.logger.info("Removing current session (#{session[:current_user]})") - session.destroy - @current_user = nil - if params[:token].nil? # Send to authenticate + clear_current_session + + # Start SSO roundtrip if we're not passed a token + if params[:token].nil? # Record this token and nonce in the session session[@sso.token] = @sso.nonce - # Send to authorization + # Send to SSO authenticator redirect_to @sso.request_uri and return end - # Validate authentication + # Validate authentication params from SSO begin @sso.parse(params) rescue ArgumentError => e - return 403, e.message + Rails.logger.debug("SSO request failed: #{e.message}") + return :forbidden end + # Resolve SSO and finish authentication case @sso.status - when :unauthorized - Rails.logger.info("Authentication failed!") - return 403 when :ok Rails.logger.info("Authentication succeeded!") - @current_user = User.find_by(external_id: @sso.user_info[:external_id]) || - begin - Rails.logger.info('new user...') - u = User.create( - external_id: @sso.user_info[:external_id], - avatar_url: @sso.user_info[:avatar_url], - email: @sso.user_info[:email], - name: @sso.user_info[:name], - username: @sso.user_info[:username]) - Rails.logger.info('created user %s' % u.inspect) - u - rescue Exception => e - raise - end - # Update user agents - if @current_user.present? - AgencyWatcherJob.perform_later(@current_user, @sso.user_info[:groups].split(',')) - end - # Save User ID in session - session[:current_user] = @current_user[:external_id] + find_or_create_current_user + perform_background_jobs + update_current_session + when :unauthorized + Rails.logger.info("Authentication failed!") end + return :forbidden unless @current_user.present? + # TODO add some memory of previously called URL and return there redirect_to '/my/dashboard' end @@ -73,4 +55,54 @@ class WelcomeController < ApplicationController session.destroy render :index end + + private + + # Ensure nobody tries silly things with our session + def validate_token_format! + if params[:token].present? && !params[:token].match?(/[a-z0-9]{32}/) + raise(ArgumentError, "Token invalid") + end + end + + # Remove any current session + def clear_current_session + Rails.logger.info("Removing current session (#{session[:current_user]})") + session.destroy + @current_user = nil + end + + # Set @current_user to existing or new User record from SSO user info + def find_or_create_current_user + @current_user = User.find_by(external_id: @sso.user_info[:external_id]) || + begin + Rails.logger.info('new user...') + u = User.create( + external_id: @sso.user_info[:external_id], + avatar_url: @sso.user_info[:avatar_url], + email: @sso.user_info[:email], + name: @sso.user_info[:name], + username: @sso.user_info[:username]) + Rails.logger.info('created user %s' % u.inspect) + u + rescue Exception => e + Rails.logger.warning("#{e.type}: #{e.message}") + end + end + + # Update user agents + def perform_background_jobs + if @current_user.present? + AgencyWatcherJob.perform_later(@current_user, @sso.user_info[:groups].split(',')) + end + end + + # Save User ID and current agent in session + def update_current_session + if @current_user.present? + session[:current_user] = @current_user[:external_id] + # TODO: make this a bit smarter + session[:current_agent] = @current_user&.agents&.pluck(:name)&.last + end + end end -- cgit v1.2.3