class WelcomeController < ApplicationController # GET / def index end # GET /authenticate(/:token) # Discourse SSO Authentication def authenticate validate_token_format! # Try an ongoing SSO or create a new one @sso = SSO::FromDiscourse.new(token: params[:token], nonce: session[params[:token]]) 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 SSO authenticator redirect_to @sso.request_uri and return end # Validate authentication params from SSO begin @sso.parse(params) rescue ArgumentError => e Rails.logger.debug("SSO request failed: #{e.message}") return :forbidden end # Resolve SSO and finish authentication case @sso.status when :ok Rails.logger.info("Authentication succeeded!") 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 # GET /dashboard def dashboard redirect_to '/authenticate' and return unless current_user.present? end # GET /logout def logout 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