check nonce

This commit is contained in:
simon lehericey 2022-04-11 13:11:54 +02:00
parent 9938586d96
commit 1dcfb2509f
3 changed files with 44 additions and 9 deletions

View file

@ -4,20 +4,23 @@ class AgentConnect::AgentController < ApplicationController
before_action :check_state, only: [:callback]
STATE_COOKIE_NAME = :agentConnect_state
NONCE_COOKIE_NAME = :agentConnect_nonce
def index
end
def login
uri, state = AgentConnectService.authorization_uri
uri, state, nonce = AgentConnectService.authorization_uri
cookies.encrypted[STATE_COOKIE_NAME] = state
cookies.encrypted[NONCE_COOKIE_NAME] = nonce
redirect_to uri
end
def callback
user_info = AgentConnectService.user_info(params[:code])
user_info = AgentConnectService.user_info(params[:code], cookies.encrypted[NONCE_COOKIE_NAME])
cookies.encrypted[NONCE_COOKIE_NAME] = nil
instructeur = Instructeur.find_by(agent_connect_id: user_info['sub'])

View file

@ -1,4 +1,6 @@
class AgentConnectService
include OpenIDConnect
def self.enabled?
ENV.fetch("AGENT_CONNECT_ENABLED", "enabled") == "enabled"
end
@ -7,22 +9,40 @@ class AgentConnectService
client = AgentConnectClient.new
state = SecureRandom.hex(16)
nonce = SecureRandom.hex(16)
uri = client.authorization_uri(
scope: [:openid, :email],
state: state,
nonce: SecureRandom.hex(16),
nonce: nonce,
acr_values: 'eidas1'
)
[uri, state]
[uri, state, nonce]
end
def self.user_info(code)
def self.user_info(code, nonce)
client = AgentConnectClient.new(code)
client.access_token!(client_auth_method: :secret)
access_token = client.access_token!(client_auth_method: :secret)
discover = find_discover
id_token = ResponseObject::IdToken.decode(access_token.id_token, discover.jwks)
id_token.verify!(
client_id: AGENT_CONNECT[:identifier],
issuer: discover.issuer,
nonce: nonce
)
access_token
.userinfo!
.raw_attributes
end
private
def self.find_discover
Discovery::Provider::Config.discover!("#{AGENT_CONNECT_BASE_URL}/api/v2")
end
end

View file

@ -2,15 +2,22 @@ describe AgentConnect::AgentController, type: :controller do
describe '#login' do
before { get :login }
it { expect(state_cookie).not_to be_nil }
it do
expect(state_cookie).not_to be_nil
expect(nonce_cookie).not_to be_nil
end
end
describe '#callback' do
let(:email) { 'i@email.com' }
let(:original_state) { 'original_state' }
let(:nonce) { 'nonce' }
subject { get :callback, params: { code: code, state: state } }
before { cookies.encrypted[controller.class::STATE_COOKIE_NAME] = original_state }
before do
cookies.encrypted[controller.class::STATE_COOKIE_NAME] = original_state
cookies.encrypted[controller.class::NONCE_COOKIE_NAME] = nonce
end
context 'when the callback code is correct' do
let(:code) { 'correct' }
@ -19,7 +26,7 @@ describe AgentConnect::AgentController, type: :controller do
context 'and user_info returns some info' do
before do
expect(AgentConnectService).to receive(:user_info).and_return(user_info)
expect(AgentConnectService).to receive(:user_info).with(code, nonce).and_return(user_info)
end
context 'and the instructeur does not have an account yet' do
@ -37,6 +44,7 @@ describe AgentConnect::AgentController, type: :controller do
expect(last_user.instructeur.agent_connect_id).to eq('sub')
expect(response).to redirect_to(instructeur_procedures_path)
expect(state_cookie).to be_nil
expect(nonce_cookie).to be_nil
end
end
@ -116,4 +124,8 @@ describe AgentConnect::AgentController, type: :controller do
def state_cookie
cookies.encrypted[controller.class::STATE_COOKIE_NAME]
end
def nonce_cookie
cookies.encrypted[controller.class::NONCE_COOKIE_NAME]
end
end