From e58ae3f828c4fc3c93ae7da5022ac6a043400dbd Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 3 Oct 2023 13:32:33 -0400 Subject: [PATCH 1/5] LG-11110: Allow user to reauthenticate with any MFA method changelog: Bug Fixes, MFA Setup, Fix issue preventing user from reauthenticating with an existing MFA method when adding a new method for strict AAL2 request --- .../two_factor_login_options_presenter.rb | 9 +- .../phishing_resistant_required_spec.rb | 93 +++++++------ ...two_factor_login_options_presenter_spec.rb | 130 +++++++++++++----- 3 files changed, 158 insertions(+), 74 deletions(-) diff --git a/app/presenters/two_factor_login_options_presenter.rb b/app/presenters/two_factor_login_options_presenter.rb index c9ddcdd710e..ed30b21e87f 100644 --- a/app/presenters/two_factor_login_options_presenter.rb +++ b/app/presenters/two_factor_login_options_presenter.rb @@ -1,8 +1,9 @@ class TwoFactorLoginOptionsPresenter < TwoFactorAuthCode::GenericDeliveryPresenter include ActionView::Helpers::TranslationHelper - attr_reader :user, :phishing_resistant_required, :piv_cac_required + attr_reader :user, :reauthentication_context, :phishing_resistant_required, :piv_cac_required + alias_method :reauthentication_context?, :reauthentication_context alias_method :phishing_resistant_required?, :phishing_resistant_required alias_method :piv_cac_required?, :piv_cac_required @@ -35,6 +36,8 @@ def info end def restricted_options_warning_text + return if reauthentication_context? + if piv_cac_required? t('two_factor_authentication.aal2_request.piv_cac_only_html', sp_name:) elsif phishing_resistant_required? @@ -46,9 +49,9 @@ def options return @options if defined?(@options) mfa = MfaContext.new(user) - if @piv_cac_required + if piv_cac_required? && !reauthentication_context? configurations = mfa.piv_cac_configurations - elsif @phishing_resistant_required + elsif phishing_resistant_required? && !reauthentication_context? configurations = mfa.phishing_resistant_configurations else configurations = mfa.two_factor_configurations diff --git a/spec/features/openid_connect/phishing_resistant_required_spec.rb b/spec/features/openid_connect/phishing_resistant_required_spec.rb index 9c1914b3236..766af0c3628 100644 --- a/spec/features/openid_connect/phishing_resistant_required_spec.rb +++ b/spec/features/openid_connect/phishing_resistant_required_spec.rb @@ -2,20 +2,60 @@ RSpec.describe 'Phishing-resistant authentication required in an OIDC context' do include OidcAuthHelper + include WebAuthnHelper - describe 'OpenID Connect requesting AAL3 authentication' do - context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - user = user_with_2fa + shared_examples 'user required to set up phishing-resistant authenticator' do + it 'sends user to set up phishing-resistant auth' do + sign_in_live_with_2fa(user) - visit_idp_from_ial1_oidc_sp_requesting_aal3(prompt: 'select_account') - sign_in_live_with_2fa(user) + expect(page).to have_current_path(authentication_methods_setup_path) + expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) + expect(page).to have_xpath("//img[@alt='important alert icon']") + + # Validate that user is not allowed to continue without making a selection. + click_continue + expect(page).to have_current_path(authentication_methods_setup_path) + expect(page).to have_content(t('errors.two_factor_auth_setup.must_select_option')) + + # Regression (LG-11110): Ensure the user can reauthenticate with any existing configuration, + # not limited based on phishing-resistant requirement. + travel (IdentityConfig.store.reauthn_window + 1).seconds do + check t('two_factor_authentication.two_factor_choice_options.webauthn') + click_continue + + expect(page).to have_content(t('two_factor_authentication.login_options.sms')) + expect(page).to have_content(t('two_factor_authentication.login_options.voice')) + + choose t('two_factor_authentication.login_options.sms') + click_continue - expect(current_url).to eq(authentication_methods_setup_url) + fill_in_code_with_last_phone_otp + click_submit_default + + # LG-11193: Currently the user is redirected back to the MFA setup selection after + # reauthenticating. This should be improved to remember their original selection. + expect(page).to have_current_path(authentication_methods_setup_path) expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") + mock_webauthn_setup_challenge + check t('two_factor_authentication.two_factor_choice_options.webauthn') + click_continue + + fill_in_nickname_and_click_continue + mock_press_button_on_hardware_key_on_setup + + expect(page).to have_current_path(sign_up_completed_path) end end + end + + describe 'OpenID Connect requesting AAL3 authentication' do + context 'user does not have phishing-resistant auth configured' do + let(:user) { create(:user, :fully_registered, :with_phone) } + + before { visit_idp_from_ial1_oidc_sp_requesting_aal3(prompt: 'select_account') } + + it_behaves_like 'user required to set up phishing-resistant authenticator' + end context 'user has phishing-resistant auth configured' do context 'with piv cac configured' do @@ -65,16 +105,11 @@ describe 'OpenID Connect requesting phishing-resistant authentication' do context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - user = user_with_2fa + let(:user) { create(:user, :fully_registered, :with_phone) } - visit_idp_from_ial1_oidc_sp_requesting_phishing_resistant(prompt: 'select_account') - sign_in_live_with_2fa(user) + before { visit_idp_from_ial1_oidc_sp_requesting_phishing_resistant(prompt: 'select_account') } - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") - end + it_behaves_like 'user required to set up phishing-resistant authenticator' end context 'user has phishing-resistant auth configured' do @@ -125,31 +160,11 @@ describe 'ServiceProvider configured to default to AAL3 authentication' do context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - user = user_with_2fa + let(:user) { create(:user, :fully_registered, :with_phone) } - visit_idp_from_ial1_oidc_sp_defaulting_to_aal3(prompt: 'select_account') - sign_in_live_with_2fa(user) - - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") - end + before { visit_idp_from_ial1_oidc_sp_defaulting_to_aal3(prompt: 'select_account') } - it 'throws an error if user doesnt select phishing-resistant auth' do - user = user_with_2fa - - visit_idp_from_ial1_oidc_sp_defaulting_to_aal3(prompt: 'select_account') - sign_in_live_with_2fa(user) - - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") - - click_continue - - expect(page).to have_content(t('errors.two_factor_auth_setup.must_select_option')) - end + it_behaves_like 'user required to set up phishing-resistant authenticator' end context 'user has phishing-resistant auth configured' do diff --git a/spec/presenters/two_factor_login_options_presenter_spec.rb b/spec/presenters/two_factor_login_options_presenter_spec.rb index 926e6204f88..66192f8aaa3 100644 --- a/spec/presenters/two_factor_login_options_presenter_spec.rb +++ b/spec/presenters/two_factor_login_options_presenter_spec.rb @@ -61,18 +61,95 @@ ) end - context 'with multiple webauthn configurations' do - let(:user) { create(:user) } - before(:each) do - create_list(:webauthn_configuration, 2, user: user) - user.webauthn_configurations.reload + describe '#options' do + let(:user) do + create( + :user, + :fully_registered, + :with_webauthn, + :with_webauthn_platform, + :with_phone, + :with_piv_or_cac, + :with_personal_key, + :with_backup_code, + :with_authentication_app, + ) + end + + subject(:options) { presenter.options } + let(:options_classes) { options.map(&:class) } + + it 'returns classes for mfas associated with account' do + expect(options_classes).to contain_exactly( + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ) end it 'has only one webauthn selection presenter' do - webauthn_selection_presenters = presenter.options.map(&:class).select do |klass| + webauthn_selection_presenter_count = options_classes.count do |klass| klass == TwoFactorAuthentication::WebauthnSelectionPresenter end - expect(webauthn_selection_presenters.count).to eq 1 + + expect(webauthn_selection_presenter_count).to eq 1 + end + + context 'piv cac required' do + let(:piv_cac_required) { true } + + it 'filters to piv method' do + expect(options_classes).to contain_exactly( + TwoFactorAuthentication::PivCacSelectionPresenter, + ) + end + + context 'in reauthentication context' do + let(:reauthentication_context) { true } + + it 'returns all mfas associated with account' do + expect(options_classes).to contain_exactly( + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ) + end + end + end + + context 'phishing resistant required' do + let(:phishing_resistant_required) { true } + + it 'filters to phishing resistant methods' do + expect(options_classes).to contain_exactly( + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + ) + end + + context 'in reauthentication context' do + let(:reauthentication_context) { true } + + it 'returns all mfas associated with account' do + expect(options_classes).to contain_exactly( + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ) + end + end end end @@ -90,33 +167,10 @@ ) end - context 'piv cac required' do - let(:piv_cac_required) { true } - - it 'returns piv cac required warning text for app' do - expect(restricted_options_warning_text).to eq( - t('two_factor_authentication.aal2_request.piv_cac_only_html', sp_name: APP_NAME), - ) - end - - context 'with sp' do - let(:service_provider) { build(:service_provider) } - - it 'returns piv cac required warning text for service provider' do - expect(restricted_options_warning_text).to eq( - t( - 'two_factor_authentication.aal2_request.piv_cac_only_html', - sp_name: service_provider.friendly_name, - ), - ) - end - end - end - context 'with sp' do let(:service_provider) { build(:service_provider) } - it 'returns phishing resistant required warning text for service provider' do + it 'returns piv cac required warning text for service provider' do expect(restricted_options_warning_text).to eq( t( 'two_factor_authentication.aal2_request.phishing_resistant_html', @@ -125,6 +179,12 @@ ) end end + + context 'in reauthentication context' do + let(:reauthentication_context) { true } + + it { should be_nil } + end end context 'piv cac required' do @@ -139,7 +199,7 @@ context 'with sp' do let(:service_provider) { build(:service_provider) } - it 'returns piv cac required warning text for service provider' do + it 'returns phishing resistant required warning text for service provider' do expect(restricted_options_warning_text).to eq( t( 'two_factor_authentication.aal2_request.piv_cac_only_html', @@ -148,6 +208,12 @@ ) end end + + context 'in reauthentication context' do + let(:reauthentication_context) { true } + + it { should be_nil } + end end end From fde8bb939882055baf93fbdc77bd83e85bd63807 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 3 Oct 2023 13:39:46 -0400 Subject: [PATCH 2/5] Sync spec descriptions to expected text --- spec/presenters/two_factor_login_options_presenter_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/presenters/two_factor_login_options_presenter_spec.rb b/spec/presenters/two_factor_login_options_presenter_spec.rb index 66192f8aaa3..b37a846db4f 100644 --- a/spec/presenters/two_factor_login_options_presenter_spec.rb +++ b/spec/presenters/two_factor_login_options_presenter_spec.rb @@ -170,7 +170,7 @@ context 'with sp' do let(:service_provider) { build(:service_provider) } - it 'returns piv cac required warning text for service provider' do + it 'returns phishing resistant required warning text for service provider' do expect(restricted_options_warning_text).to eq( t( 'two_factor_authentication.aal2_request.phishing_resistant_html', @@ -199,7 +199,7 @@ context 'with sp' do let(:service_provider) { build(:service_provider) } - it 'returns phishing resistant required warning text for service provider' do + it 'returns piv cac required warning text for service provider' do expect(restricted_options_warning_text).to eq( t( 'two_factor_authentication.aal2_request.piv_cac_only_html', From 17a19a073f7c61bfa2e22ece153483b2968a591c Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 3 Oct 2023 13:50:04 -0400 Subject: [PATCH 3/5] Add feature specs for SAML phishing required --- .../phishing_resistant_required_spec.rb | 8 +- .../saml/phishing_resistant_required_spec.rb | 79 ++++++++++++++----- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/spec/features/openid_connect/phishing_resistant_required_spec.rb b/spec/features/openid_connect/phishing_resistant_required_spec.rb index 766af0c3628..bb9bdc75fc6 100644 --- a/spec/features/openid_connect/phishing_resistant_required_spec.rb +++ b/spec/features/openid_connect/phishing_resistant_required_spec.rb @@ -4,7 +4,7 @@ include OidcAuthHelper include WebAuthnHelper - shared_examples 'user required to set up phishing-resistant authenticator' do + shared_examples 'setting up phishing-resistant authenticator in an OIDC context' do it 'sends user to set up phishing-resistant auth' do sign_in_live_with_2fa(user) @@ -54,7 +54,7 @@ before { visit_idp_from_ial1_oidc_sp_requesting_aal3(prompt: 'select_account') } - it_behaves_like 'user required to set up phishing-resistant authenticator' + it_behaves_like 'setting up phishing-resistant authenticator in an OIDC context' end context 'user has phishing-resistant auth configured' do @@ -109,7 +109,7 @@ before { visit_idp_from_ial1_oidc_sp_requesting_phishing_resistant(prompt: 'select_account') } - it_behaves_like 'user required to set up phishing-resistant authenticator' + it_behaves_like 'setting up phishing-resistant authenticator in an OIDC context' end context 'user has phishing-resistant auth configured' do @@ -164,7 +164,7 @@ before { visit_idp_from_ial1_oidc_sp_defaulting_to_aal3(prompt: 'select_account') } - it_behaves_like 'user required to set up phishing-resistant authenticator' + it_behaves_like 'setting up phishing-resistant authenticator in an OIDC context' end context 'user has phishing-resistant auth configured' do diff --git a/spec/features/saml/phishing_resistant_required_spec.rb b/spec/features/saml/phishing_resistant_required_spec.rb index efd2c403447..414a5f84d31 100644 --- a/spec/features/saml/phishing_resistant_required_spec.rb +++ b/spec/features/saml/phishing_resistant_required_spec.rb @@ -2,22 +2,65 @@ RSpec.describe 'Phishing-resistant authentication required in an SAML context' do include SamlAuthHelper + include WebAuthnHelper + + shared_examples 'setting up phishing-resistant authenticator in an SAML context' do + it 'sends user to set up phishing-resistant auth' do + expect(page).to have_current_path(authentication_methods_setup_path) + expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) + expect(page).to have_xpath("//img[@alt='important alert icon']") + + # Validate that user is not allowed to continue without making a selection. + click_continue + expect(page).to have_current_path(authentication_methods_setup_path) + expect(page).to have_content(t('errors.two_factor_auth_setup.must_select_option')) + + # Regression (LG-11110): Ensure the user can reauthenticate with any existing configuration, + # not limited based on phishing-resistant requirement. + travel (IdentityConfig.store.reauthn_window + 1).seconds do + check t('two_factor_authentication.two_factor_choice_options.webauthn') + click_continue + + expect(page).to have_content(t('two_factor_authentication.login_options.sms')) + expect(page).to have_content(t('two_factor_authentication.login_options.voice')) + + choose t('two_factor_authentication.login_options.sms') + click_continue + + fill_in_code_with_last_phone_otp + click_submit_default + + # LG-11193: Currently the user is redirected back to the MFA setup selection after + # reauthenticating. This should be improved to remember their original selection. + expect(page).to have_current_path(authentication_methods_setup_path) + expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) + mock_webauthn_setup_challenge + check t('two_factor_authentication.two_factor_choice_options.webauthn') + click_continue + + fill_in_nickname_and_click_continue + mock_press_button_on_hardware_key_on_setup + + expect(page).to have_current_path(sign_up_completed_path) + end + end + end describe 'SAML ServiceProvider requesting phishing-resistant authentication' do context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - sign_in_and_2fa_user(user_with_2fa) + let(:user) { create(:user, :proofed, :with_phone) } + + before do + sign_in_and_2fa_user(user) visit_saml_authn_request_url( overrides: { issuer: sp1_issuer, authn_context: Saml::Idp::Constants::AAL2_PHISHING_RESISTANT_AUTHN_CONTEXT_CLASSREF, }, ) - - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") end + + it_behaves_like 'setting up phishing-resistant authenticator in an SAML context' end context 'user has phishing-resistant auth configured' do @@ -76,18 +119,18 @@ describe 'SAML ServiceProvider requesting AAL3 authentication' do context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - sign_in_and_2fa_user(user_with_2fa) + let(:user) { create(:user, :proofed, :with_phone) } + + before do + sign_in_and_2fa_user(user) visit_saml_authn_request_url( overrides: { issuer: sp1_issuer, authn_context: Saml::Idp::Constants::AAL3_AUTHN_CONTEXT_CLASSREF }, ) - - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") end + + it_behaves_like 'setting up phishing-resistant authenticator in an SAML context' end context 'user has phishing-resistant auth configured' do @@ -143,18 +186,18 @@ describe 'SAML ServiceProvider configured to default to AAL3 authentication' do context 'user does not have phishing-resistant auth configured' do - it 'sends user to set up phishing-resistant auth' do - sign_in_and_2fa_user(user_with_2fa) + let(:user) { create(:user, :proofed, :with_phone) } + + before do + sign_in_and_2fa_user(user) visit_saml_authn_request_url( overrides: { issuer: aal3_issuer, authn_context: nil }, ) - - expect(current_url).to eq(authentication_methods_setup_url) - expect(page).to have_content(t('two_factor_authentication.two_factor_aal3_choice')) - expect(page).to have_xpath("//img[@alt='important alert icon']") end + + it_behaves_like 'setting up phishing-resistant authenticator in an SAML context' end context 'user has phishing-resistant auth configured' do From 83b9162d75f3279ce40651e371ad3bbefbd3cb5d Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Wed, 4 Oct 2023 11:30:03 -0400 Subject: [PATCH 4/5] Update options spec to enforce order See: https://github.com/18F/identity-idp/pull/9304/files#r1345773215 --- ...two_factor_login_options_presenter_spec.rb | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/spec/presenters/two_factor_login_options_presenter_spec.rb b/spec/presenters/two_factor_login_options_presenter_spec.rb index b37a846db4f..ce1ace484d0 100644 --- a/spec/presenters/two_factor_login_options_presenter_spec.rb +++ b/spec/presenters/two_factor_login_options_presenter_spec.rb @@ -80,14 +80,16 @@ let(:options_classes) { options.map(&:class) } it 'returns classes for mfas associated with account' do - expect(options_classes).to contain_exactly( - TwoFactorAuthentication::SmsSelectionPresenter, - TwoFactorAuthentication::VoiceSelectionPresenter, - TwoFactorAuthentication::WebauthnSelectionPresenter, - TwoFactorAuthentication::BackupCodeSelectionPresenter, - TwoFactorAuthentication::PivCacSelectionPresenter, - TwoFactorAuthentication::SignInAuthAppSelectionPresenter, - TwoFactorAuthentication::PersonalKeySelectionPresenter, + expect(options_classes).to eq( + [ + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ], ) end @@ -103,23 +105,23 @@ let(:piv_cac_required) { true } it 'filters to piv method' do - expect(options_classes).to contain_exactly( - TwoFactorAuthentication::PivCacSelectionPresenter, - ) + expect(options_classes).to eq([TwoFactorAuthentication::PivCacSelectionPresenter]) end context 'in reauthentication context' do let(:reauthentication_context) { true } it 'returns all mfas associated with account' do - expect(options_classes).to contain_exactly( - TwoFactorAuthentication::SmsSelectionPresenter, - TwoFactorAuthentication::VoiceSelectionPresenter, - TwoFactorAuthentication::WebauthnSelectionPresenter, - TwoFactorAuthentication::BackupCodeSelectionPresenter, - TwoFactorAuthentication::PivCacSelectionPresenter, - TwoFactorAuthentication::SignInAuthAppSelectionPresenter, - TwoFactorAuthentication::PersonalKeySelectionPresenter, + expect(options_classes).to eq( + [ + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ], ) end end @@ -129,9 +131,11 @@ let(:phishing_resistant_required) { true } it 'filters to phishing resistant methods' do - expect(options_classes).to contain_exactly( - TwoFactorAuthentication::WebauthnSelectionPresenter, - TwoFactorAuthentication::PivCacSelectionPresenter, + expect(options_classes).to eq( + [ + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + ], ) end @@ -139,14 +143,16 @@ let(:reauthentication_context) { true } it 'returns all mfas associated with account' do - expect(options_classes).to contain_exactly( - TwoFactorAuthentication::SmsSelectionPresenter, - TwoFactorAuthentication::VoiceSelectionPresenter, - TwoFactorAuthentication::WebauthnSelectionPresenter, - TwoFactorAuthentication::BackupCodeSelectionPresenter, - TwoFactorAuthentication::PivCacSelectionPresenter, - TwoFactorAuthentication::SignInAuthAppSelectionPresenter, - TwoFactorAuthentication::PersonalKeySelectionPresenter, + expect(options_classes).to eq( + [ + TwoFactorAuthentication::SmsSelectionPresenter, + TwoFactorAuthentication::VoiceSelectionPresenter, + TwoFactorAuthentication::WebauthnSelectionPresenter, + TwoFactorAuthentication::BackupCodeSelectionPresenter, + TwoFactorAuthentication::PivCacSelectionPresenter, + TwoFactorAuthentication::SignInAuthAppSelectionPresenter, + TwoFactorAuthentication::PersonalKeySelectionPresenter, + ], ) end end From aab74c1ee8835b5207ace092089cd895dd45e045 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 5 Oct 2023 08:28:57 -0400 Subject: [PATCH 5/5] Bump CodeClimate