diff --git a/app/controllers/saml_idp_controller.rb b/app/controllers/saml_idp_controller.rb index 08ce3541682..5a098d2de28 100644 --- a/app/controllers/saml_idp_controller.rb +++ b/app/controllers/saml_idp_controller.rb @@ -90,7 +90,7 @@ def redirect_to_verification_url end def profile_or_identity_needs_verification_or_decryption? - return false unless ial2_requested? + return false unless ial_context.ial2_or_greater? profile_needs_verification? || identity_needs_verification? || identity_needs_decryption? end diff --git a/app/presenters/saml_request_presenter.rb b/app/presenters/saml_request_presenter.rb index d411e0a09fd..1535af95c85 100644 --- a/app/presenters/saml_request_presenter.rb +++ b/app/presenters/saml_request_presenter.rb @@ -23,7 +23,7 @@ def initialize(request:, service_provider:) end def requested_attributes - if ial2_authn_context? || ialmax_authn_context? + if ial2_authn_context? || ial2_strict_authn_context? || ialmax_authn_context? bundle.map { |attr| ATTRIBUTE_TO_FRIENDLY_NAME_MAP[attr] }.compact.uniq else attrs = [:email] @@ -40,6 +40,10 @@ def ial2_authn_context? (Saml::Idp::Constants::IAL2_AUTHN_CONTEXTS & authn_context).present? end + def ial2_strict_authn_context? + authn_context.include? Saml::Idp::Constants::IAL2_STRICT_AUTHN_CONTEXT_CLASSREF + end + def ialmax_authn_context? authn_context.include? Saml::Idp::Constants::IALMAX_AUTHN_CONTEXT_CLASSREF end diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 11e848e4f77..8e283a82304 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -442,7 +442,15 @@ def name_id_version(format_urn) ) end - context 'with IAL2 and the identity is already verified' do + shared_examples 'a verified identity' do |authn_context, ial| + let(:ial2_settings) do + saml_settings( + overrides: { + issuer: sp1_issuer, + authn_context: authn_context, + }, + ) + end let(:user) { create(:profile, :active, :verified).user } let(:pii) do Pii::Attributes.new_from_hash( @@ -457,7 +465,7 @@ def name_id_version(format_urn) ial2_authnrequest = saml_authn_request_url( overrides: { issuer: sp1_issuer, - authn_context: Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF, + authn_context: authn_context, }, ) raw_req = CGI.unescape ial2_authnrequest.split('SAMLRequest').last @@ -476,7 +484,7 @@ def name_id_version(format_urn) before do stub_sign_in(user) - IdentityLinker.new(user, sp1).link_identity(ial: 2) + IdentityLinker.new(user, sp1).link_identity(ial: ial) user.identities.last.update!( verified_attributes: %w[given_name family_name social_security_number address], ) @@ -491,9 +499,9 @@ def name_id_version(format_urn) saml_get_auth(ial2_settings) end - it 'sets identity ial to 2' do + it 'sets identity ial' do saml_get_auth(ial2_settings) - expect(user.identities.last.ial).to eq(2) + expect(user.identities.last.ial).to eq(ial) end it 'does not redirect the user to the IdV URL' do @@ -521,23 +529,23 @@ def name_id_version(format_urn) stub_analytics expect(@analytics).to receive(:track_event). with('SAML Auth Request', - requested_ial: Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF, + requested_ial: authn_context, service_provider: sp1_issuer) expect(@analytics).to receive(:track_event). with(Analytics::SAML_AUTH, success: true, errors: {}, nameid_format: Saml::Idp::Constants::NAME_ID_FORMAT_PERSISTENT, - authn_context: ['http://idmanagement.gov/ns/assurance/ial/2'], + authn_context: [authn_context], authn_context_comparison: 'exact', - requested_ial: Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF, + requested_ial: authn_context, service_provider: sp1_issuer, endpoint: '/api/saml/auth2022', idv: false, finish_profile: false) expect(@analytics).to receive(:track_event). with(Analytics::SP_REDIRECT_INITIATED, - ial: 2) + ial: ial) allow(controller).to receive(:identity_needs_verification?).and_return(false) saml_get_auth(ial2_settings) @@ -553,6 +561,22 @@ def name_id_version(format_urn) end end + context 'with IAL2 and the identity is already verified' do + it_behaves_like 'a verified identity', + Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF, + Idp::Constants::IAL2 + end + + context 'with IAL2 strict and the identity is already verified' do + before do + allow(IdentityConfig.store).to receive(:liveness_checking_enabled).and_return(true) + end + + it_behaves_like 'a verified identity', + Saml::Idp::Constants::IAL2_STRICT_AUTHN_CONTEXT_CLASSREF, + Idp::Constants::IAL2_STRICT + end + context 'with IAL2 and the identity is not already verified' do it 'redirects to IdV URL for IAL2 proofer' do user = create(:user, :signed_up)