Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/decorators/service_provider_session_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ def mfa_expiration_interval
aal_2_expiration = IdentityConfig.store.remember_device_expiration_hours_aal_2.hours
return aal_2_expiration if sp_aal > 1
return aal_2_expiration if sp_ial > 1
return aal_2_expiration if requested_aal > 1

aal_1_expiration
end

Expand Down Expand Up @@ -123,6 +125,10 @@ def sp_ial
sp.ial || 1
end

def requested_aal
sp_session[:aal_level_requested] || 1
end

def request_url
sp_session[:request_url] || service_provider_request.url
end
Expand Down
30 changes: 30 additions & 0 deletions spec/features/remember_device/sp_expiration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@
expect(page).to have_current_path(sign_up_completed_path)
end
end

it 'requires MFA when AAL2 request is sent after 12 hours' do
travel_to(12.hours.from_now + 1.day) do
visit_idp_from_sp_with_ial1_aal2(protocol)
sign_in_user(user)

expect(page).to have_content(t('two_factor_authentication.header_text'))
expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms))

fill_in_code_with_last_phone_otp
click_submit_default

expect(page).to have_current_path(sign_up_completed_path)
end
end
end

context "#{protocol}: visiting while already signed in" do
Expand Down Expand Up @@ -60,6 +75,21 @@
expect(page).to have_current_path(sign_up_completed_path)
end
end

it 'does require MFA when AAL2 request is sent after 12 hours' do
travel_to(12.hours.from_now + 1.day) do
visit_idp_from_sp_with_ial1_aal2(protocol)
sign_in_user(user)

expect(page).to have_content(t('two_factor_authentication.header_text'))
expect(current_path).to eq(login_two_factor_path(otp_delivery_preference: :sms))

fill_in_code_with_last_phone_otp
click_submit_default

expect(page).to have_current_path(sign_up_completed_path)
end
end
end
end

Expand Down
32 changes: 32 additions & 0 deletions spec/support/saml_auth_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,22 @@ def visit_idp_from_sp_with_ial1(sp)
end
end

def visit_idp_from_sp_with_ial1_aal2(sp)
if sp == :saml
visit_saml_authn_request_url(
overrides: { authn_context: [
Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
Saml::Idp::Constants::AAL2_AUTHN_CONTEXT_CLASSREF,
] },
)
elsif sp == :oidc
@state = SecureRandom.hex
@client_id = 'urn:gov:gsa:openidconnect:sp:server'
@nonce = SecureRandom.hex
visit_idp_from_oidc_sp_with_ial1_aal2(state: @state, client_id: @client_id, nonce: @nonce)
end
end

def visit_idp_from_oidc_sp_with_ial1(client_id:, nonce:, state: SecureRandom.hex)
visit openid_connect_authorize_path(
client_id: client_id,
Expand All @@ -245,6 +261,22 @@ def visit_idp_from_oidc_sp_with_ial1(client_id:, nonce:, state: SecureRandom.hex
)
end

def visit_idp_from_oidc_sp_with_ial1_aal2(client_id:, nonce:, state: SecureRandom.hex)
visit openid_connect_authorize_path(
client_id: client_id,
response_type: 'code',
acr_values: [
Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
Saml::Idp::Constants::AAL2_AUTHN_CONTEXT_CLASSREF,
].join(' '),
scope: 'openid email',
redirect_uri: 'http://localhost:7654/auth/result',
state: state,
prompt: 'select_account',
nonce: nonce,
)
end

def visit_idp_from_oidc_sp_with_loa1_prompt_login
state = SecureRandom.hex
client_id = 'urn:gov:gsa:openidconnect:sp:server'
Expand Down