main
1# frozen_string_literal: true
2
3class SessionsController < ApplicationController
4 ALLOWED_SAML_PARAMS = [
5 :RelayState,
6 :SAMLEncoding,
7 :SAMLRequest,
8 :SAMLResponse,
9 :SigAlg,
10 :Signature,
11 ].freeze
12 skip_before_action :verify_authenticity_token, only: [:new, :destroy]
13 skip_before_action :authenticate!, only: [:new, :show, :create, :destroy]
14 skip_before_action :authenticate_mfa!, only: [:show]
15
16 def new
17 binding = binding_for(
18 request.post? ? :http_post : :http_redirect, new_session_url
19 )
20 @saml = binding.deserialize(saml_params)
21 return render_error(:forbidden, model: @saml) if @saml.invalid?
22
23 session[:saml] = { params: saml_params.to_h, xml: @saml.to_xml }
24 redirect_to response_path if current_user?
25 rescue StandardError => error
26 logger.error(error)
27 redirect_to my_dashboard_path if current_user?
28 end
29
30 def show
31 expires_in UserSession::IDLE_TIMEOUT
32 render layout: nil
33 end
34
35 def create
36 user_params = params.require(:user).permit(:email, :password)
37 if (user = User.login(user_params[:email], user_params[:password]))
38 login(user)
39 redirect_to response_path
40 else
41 redirect_to new_session_path, error: "Invalid Credentials"
42 end
43 end
44
45 def destroy
46 binding = binding_for(:http_post, session_url)
47 if saml_params[:SAMLRequest].present?
48 saml = binding.deserialize(saml_params)
49 raise ActiveRecord::RecordInvalid.new(saml) if saml.invalid?
50 raise 'Unknown NameId' unless current_user.to_param == saml.name_id
51
52 session[:saml] = { params: saml_params.to_h, xml: saml.to_xml }
53 redirect_to response_path
54 elsif saml_params[:SAMLResponse].present?
55 saml = binding.deserialize(saml_params)
56 raise ActiveRecord::RecordInvalid.new(saml) if saml.invalid?
57
58 reset_session
59 redirect_to new_session_path
60 else
61 Current.user_session&.destroy
62 reset_session
63 redirect_to new_session_path
64 end
65 end
66
67 private
68
69 def login(user)
70 saml_data = session[:saml]
71 reset_session
72 session[:user_session_key] = user.sessions.build.access(request)
73 session[:saml] = saml_data
74 end
75
76 def binding_for(binding, location)
77 if binding == :http_post
78 Saml::Kit::Bindings::HttpPost.new(location: location)
79 else
80 Saml::Kit::Bindings::HttpRedirect.new(location: location)
81 end
82 end
83
84 def saml_params(allowed_params = ALLOWED_SAML_PARAMS)
85 @saml_params ||=
86 if request.post?
87 params.permit(*allowed_params)
88 else
89 query_string = request.query_string
90 on = query_string.include?("&") ? "&" : "&"
91 result = Hash[query_string.split(on).map { |x| x.split("=", 2) }]
92 result = result.symbolize_keys
93 result.select! { |key, _value| allowed_params.include?(key.to_sym) }
94 result
95 end
96 end
97end