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
1 change: 1 addition & 0 deletions app/controllers/concerns/idv_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def confirm_idv_session_started
def confirm_idv_needed
return if effective_user.active_profile.blank? ||
decorated_session.requested_more_recent_verification? ||
effective_user.decorate.reproof_for_irs?(service_provider: current_sp) ||
strict_ial2_upgrade_required?

redirect_to idv_activated_url
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/concerns/saml_idp_auth_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ def link_identity_from_session_data
end

def identity_needs_verification?
ial2_requested? && current_user.decorate.identity_not_verified?
ial2_requested? &&
(current_user.decorate.identity_not_verified? ||
current_user.decorate.reproof_for_irs?(service_provider: current_sp))
end

def_delegators :ial_context, :ial2_requested?
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/idv_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ class IdvController < ApplicationController
before_action :profile_needs_reactivation?, only: [:index]

def index
if decorated_session.requested_more_recent_verification?
if decorated_session.requested_more_recent_verification? ||
current_user.decorate.reproof_for_irs?(service_provider: current_sp)
verify_identity
elsif active_profile? && !strict_ial2_upgrade_required?
redirect_to idv_activated_url
Expand Down
1 change: 1 addition & 0 deletions app/controllers/openid_connect/authorization_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def identity_needs_verification?
((@authorize_form.ial2_requested? || @authorize_form.ial2_strict_requested?) &&
(current_user.decorate.identity_not_verified? ||
decorated_session.requested_more_recent_verification?)) ||
current_user.decorate.reproof_for_irs?(service_provider: current_sp) ||
identity_needs_strict_ial2_verification?
end

Expand Down
9 changes: 7 additions & 2 deletions app/decorators/user_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,13 @@ def identity_not_verified?
!identity_verified?
end

def identity_verified?
user.active_profile.present?
def identity_verified?(service_provider: nil)
user.active_profile.present? && !reproof_for_irs?(service_provider: service_provider)
end

def reproof_for_irs?(service_provider:)
service_provider&.irs_attempts_api_enabled &&
!user.active_profile&.initiating_service_provider&.irs_attempts_api_enabled
end

def active_profile_newer_than_pending_profile?
Expand Down
8 changes: 8 additions & 0 deletions spec/factories/service_providers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
end
end

trait :irs do
friendly_name { 'An IRS Service Provider' }
ial { 2 }
active { true }
irs_attempts_api_enabled { true }
redirect_uris { ['http://localhost:7654/auth/result'] }
end

factory :service_provider_without_help_text, traits: [:without_help_text]
end
end
107 changes: 107 additions & 0 deletions spec/features/users/sign_in_irs_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
require 'rails_helper'

feature 'Sign in to the IRS' do
before(:all) do
@original_capyabara_wait = Capybara.default_max_wait_time
Capybara.default_max_wait_time = 5
end

after(:all) do
Capybara.default_max_wait_time = @original_capyabara_wait
end

include IdvHelper
include SamlAuthHelper

let(:irs) { create(:service_provider, :irs) }
let(:other_irs) { create(:service_provider, :irs) }
let(:not_irs) { create(:service_provider, active: true, ial: 2) }

let(:initiating_service_provider_issuer) { irs.issuer }

let(:user) do
create(
:profile, :active, :verified,
pii: { first_name: 'John', ssn: '111223333' },
initiating_service_provider_issuer: initiating_service_provider_issuer
).user
end

context 'OIDC' do
context 'user verified with IRS returns to IRS' do
context 'user visits the same IRS SP they verified with' do
it "accepts the user's identity as verified" do
visit_idp_from_oidc_sp_with_ial2(client_id: irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(sign_up_completed_path)
end
end

context 'user visits different IRS SP than the one they verified with' do
it "accepts the user's identity as verified" do
visit_idp_from_oidc_sp_with_ial2(client_id: other_irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(sign_up_completed_path)
end
end
end

context 'user verified with other agency signs in to IRS' do
let(:initiating_service_provider_issuer) { not_irs.issuer }

it 'forces the user to re-verify their identity' do
visit_idp_from_oidc_sp_with_ial2(client_id: irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(idv_doc_auth_step_path(step: :welcome))
end
end
end

context 'SAML', js: true do
context 'user verified with IRS returns to IRS' do
context 'user visits the same IRS SP they verified with' do
it "accepts the user's identity as verified" do
visit_idp_from_saml_sp_with_ial2(issuer: irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(sign_up_completed_path)
end
end

context 'user visits different IRS SP than the one they verified with' do
it "accepts the user's identity as verified" do
visit_idp_from_saml_sp_with_ial2(issuer: other_irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(sign_up_completed_path)
end
end
end

context 'user verified with other agency signs in to IRS' do
let(:initiating_service_provider_issuer) { not_irs.issuer }

it 'forces the user to re-verify their identity' do
visit_idp_from_saml_sp_with_ial2(issuer: irs.issuer)
fill_in_credentials_and_submit(user.email, user.password)
fill_in_code_with_last_phone_otp
click_submit_default

expect(current_path).to eq(idv_doc_auth_step_path(step: :welcome))
end
end
end
end
42 changes: 23 additions & 19 deletions spec/support/features/idv_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,7 @@ def choose_idv_otp_delivery_method_voice

def visit_idp_from_sp_with_ial2(sp, **extra)
if sp == :saml
saml_overrides = {
issuer: sp1_issuer,
authn_context: [
Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF,
"#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}first_name:last_name email, ssn",
"#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}phone",
],
security: {
embed_sign: false,
},
}
if javascript_enabled?
service_provider = ServiceProvider.find_by(issuer: sp1_issuer)
acs_url = URI.parse(service_provider.acs_url)
acs_url.host = page.server.host
acs_url.port = page.server.port
service_provider.update(acs_url: acs_url.to_s)
end
visit_saml_authn_request_url(overrides: saml_overrides)
visit_idp_from_saml_sp_with_ial2
elsif sp == :oidc
@state = SecureRandom.hex
@client_id = sp_oidc_issuer
Expand All @@ -97,6 +79,28 @@ def service_provider_issuer(sp)
end
end

def visit_idp_from_saml_sp_with_ial2(issuer: sp1_issuer)
saml_overrides = {
issuer: issuer,
authn_context: [
Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF,
"#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}first_name:last_name email, ssn",
"#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}phone",
],
security: {
embed_sign: false,
},
}
if javascript_enabled?
service_provider = ServiceProvider.find_by(issuer: sp1_issuer)
acs_url = URI.parse(service_provider.acs_url)
acs_url.host = page.server.host
acs_url.port = page.server.port
service_provider.update(acs_url: acs_url.to_s)
end
visit_saml_authn_request_url(overrides: saml_overrides)
end

def visit_idp_from_oidc_sp_with_ial2(
client_id: sp_oidc_issuer,
state: SecureRandom.hex,
Expand Down