114 lines
4 KiB
Ruby
114 lines
4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# doc: https://github.com/france-connect/Documentation-AgentConnect
|
|
class AgentConnect::AgentController < ApplicationController
|
|
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
|
before_action :check_state, only: [:callback]
|
|
|
|
MON_COMPTE_PRO_IDP_ID = "71144ab3-ee1a-4401-b7b3-79b44f7daeeb"
|
|
|
|
STATE_COOKIE_NAME = :agentConnect_state
|
|
NONCE_COOKIE_NAME = :agentConnect_nonce
|
|
|
|
AC_ID_TOKEN_COOKIE_NAME = :agentConnect_id_token
|
|
REDIRECT_TO_AC_LOGIN_COOKIE_NAME = :redirect_to_ac_login
|
|
|
|
def index
|
|
end
|
|
|
|
def login
|
|
uri, state, nonce = AgentConnectService.authorization_uri
|
|
|
|
cookies.encrypted[STATE_COOKIE_NAME] = { value: state, secure: Rails.env.production?, httponly: true }
|
|
cookies.encrypted[NONCE_COOKIE_NAME] = { value: nonce, secure: Rails.env.production?, httponly: true }
|
|
|
|
redirect_to uri, allow_other_host: true
|
|
end
|
|
|
|
def callback
|
|
user_info, id_token, amr = AgentConnectService.user_info(params[:code], cookies.encrypted[NONCE_COOKIE_NAME])
|
|
cookies.delete NONCE_COOKIE_NAME
|
|
|
|
if user_info['idp_id'] == MON_COMPTE_PRO_IDP_ID &&
|
|
!amr.include?('mfa') &&
|
|
Flipper.enabled?(:agent_connect_2fa, Struct.new(:flipper_id).new(flipper_id: user_info['email']))
|
|
# we need the id_token to disconnect the agent connect session later.
|
|
# we cannot store it in the instructeur model because the user is not yet created
|
|
# so we store it in a encrypted cookie
|
|
cookies.encrypted[AC_ID_TOKEN_COOKIE_NAME] = id_token
|
|
return redirect_to agent_connect_explanation_2fa_path
|
|
end
|
|
|
|
instructeur = Instructeur.find_by(users: { email: santized_email(user_info) })
|
|
|
|
if instructeur.nil?
|
|
user = User.create_or_promote_to_instructeur(santized_email(user_info), Devise.friendly_token[0, 20], agent_connect: true)
|
|
instructeur = user.instructeur
|
|
end
|
|
|
|
instructeur.update!(agent_connect_id_token: id_token)
|
|
instructeur.user.update!(email_verified_at: Time.zone.now)
|
|
|
|
aci = AgentConnectInformation.find_or_initialize_by(instructeur:, sub: user_info['sub'])
|
|
aci.update(user_info.slice('given_name', 'usual_name', 'email', 'sub', 'siret', 'organizational_unit', 'belonging_population', 'phone').merge(amr:))
|
|
|
|
sign_in(:user, instructeur.user)
|
|
|
|
redirect_to instructeur_procedures_path
|
|
|
|
rescue Rack::OAuth2::Client::Error => e
|
|
Rails.logger.error e.message
|
|
redirect_france_connect_error_connection
|
|
end
|
|
|
|
def explanation_2fa
|
|
end
|
|
|
|
# Special callback from MonComptePro juste after 2FA configuration
|
|
# then:
|
|
# - the current user is disconnected from the AgentConnect session by redirecting to the AgentConnect logout endpoint
|
|
# - the user is redirected to User::SessionsController#logout by agent connect (no choice)
|
|
# - the cookie redirect_to_ac_login is detected and the controller redirects to the relogin_after_2fa_config page
|
|
# - finally, the user clicks on the button to reconnect to the AgentConnect session
|
|
def logout_from_mcp
|
|
sign_out(:user) if user_signed_in?
|
|
|
|
id_token = cookies.encrypted[AC_ID_TOKEN_COOKIE_NAME]
|
|
cookies.delete(AC_ID_TOKEN_COOKIE_NAME)
|
|
|
|
return redirect_to root_path if id_token.blank?
|
|
|
|
cookies.encrypted[REDIRECT_TO_AC_LOGIN_COOKIE_NAME] = true
|
|
|
|
redirect_to AgentConnectService.logout_url(id_token, host_with_port: request.host_with_port), allow_other_host: true
|
|
end
|
|
|
|
def relogin_after_2fa_config
|
|
end
|
|
|
|
private
|
|
|
|
def santized_email(user_info)
|
|
user_info['email'].strip.downcase
|
|
end
|
|
|
|
def redirect_to_login_if_fc_aborted
|
|
if params[:code].blank?
|
|
redirect_to new_user_session_path
|
|
end
|
|
end
|
|
|
|
def redirect_france_connect_error_connection
|
|
flash.alert = t('errors.messages.france_connect.connexion')
|
|
redirect_to(new_user_session_path)
|
|
end
|
|
|
|
def check_state
|
|
if cookies.encrypted[STATE_COOKIE_NAME] != params[:state]
|
|
flash.alert = t('errors.messages.france_connect.connexion')
|
|
redirect_to(new_user_session_path)
|
|
else
|
|
cookies.delete STATE_COOKIE_NAME
|
|
end
|
|
end
|
|
end
|