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/saml_idp_auth_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def ial_context
ial: requested_ial_authn_context,
service_provider: saml_request_service_provider,
authn_context_comparison: saml_request.requested_authn_context_comparison,
user: current_user,
)
end

Expand Down
12 changes: 11 additions & 1 deletion app/controllers/openid_connect/authorization_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,17 @@ def pii_requested_but_locked?
end

def track_events
analytics.track_event(Analytics::SP_REDIRECT_INITIATED, ial: sp_session_ial)
event_ial_context = IalContext.new(
ial: @authorize_form.ial,
service_provider: @authorize_form.service_provider,
user: current_user,
)

analytics.track_event(
Analytics::SP_REDIRECT_INITIATED,
ial: event_ial_context.ial,
billed_ial: event_ial_context.bill_for_ial_1_or_2,
)
track_billing_events
end
end
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/saml_idp_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,11 @@ def render_template_for(message, action_url, type)
end

def track_events
analytics.track_event(Analytics::SP_REDIRECT_INITIATED, ial: ial_context.ial)
analytics.track_event(
Analytics::SP_REDIRECT_INITIATED,
ial: ial_context.ial,
billed_ial: ial_context.bill_for_ial_1_or_2,
)
track_billing_events
end
end
8 changes: 4 additions & 4 deletions app/forms/openid_connect_authorize_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def ial_context
@ial_context ||= IalContext.new(ial: ial, service_provider: service_provider)
end

def ial
Saml::Idp::Constants::AUTHN_CONTEXT_CLASSREF_TO_IAL[ial_values.sort.max]
end

def_delegators :ial_context,
:ial2_or_greater?,
:ial2_requested?,
Expand Down Expand Up @@ -195,10 +199,6 @@ def validate_verified_within_duration
false
end

def ial
Saml::Idp::Constants::AUTHN_CONTEXT_CLASSREF_TO_IAL[ial_values.sort.max]
end

def extra_analytics_attributes
{
client_id: client_id,
Expand Down
159 changes: 155 additions & 4 deletions spec/controllers/openid_connect/authorization_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@
acr_values: 'http://idmanagement.gov/ns/assurance/ial/1',
scope: 'openid')
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: 1)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 1,
billed_ial: 1,
)

IdentityLinker.new(user, service_provider).link_identity(ial: 1)
user.identities.last.update!(verified_attributes: %w[given_name family_name birthdate])
Expand Down Expand Up @@ -115,8 +118,11 @@
acr_values: 'http://idmanagement.gov/ns/assurance/ial/2',
scope: 'openid profile')
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: 2)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 2,
billed_ial: 2,
)

IdentityLinker.new(user, service_provider).link_identity(ial: 2)
user.identities.last.update!(
Expand Down Expand Up @@ -167,6 +173,151 @@
end
end

context 'with ialmax requested' do
before { params[:acr_values] = Saml::Idp::Constants::IALMAX_AUTHN_CONTEXT_CLASSREF }

context 'account is already verified' do
let(:user) do
create(
:profile, :active, :verified, proofing_components: { liveness_check: true }
).user
end

it 'redirects to the redirect_uri immediately when pii is unlocked' do
IdentityLinker.new(user, service_provider).link_identity(ial: 3)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)
allow(controller).to receive(:pii_requested_but_locked?).and_return(false)
action

expect(response).to redirect_to(/^#{params[:redirect_uri]}/)
end

it 'redirects to the password capture url when pii is locked' do
IdentityLinker.new(user, service_provider).link_identity(ial: 3)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)
allow(controller).to receive(:pii_requested_but_locked?).and_return(true)
action

expect(response).to redirect_to(capture_password_url)
end

it 'tracks IAL2 authentication event' do
stub_analytics
expect(@analytics).to receive(:track_event).
with(Analytics::OPENID_CONNECT_REQUEST_AUTHORIZATION,
success: true,
client_id: client_id,
errors: {},
unauthorized_scope: false,
user_fully_authenticated: true,
acr_values: 'http://idmanagement.gov/ns/assurance/ial/0',
scope: 'openid profile')
expect(@analytics).to receive(:track_event).
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 0,
billed_ial: 2,
)

IdentityLinker.new(user, service_provider).link_identity(ial: 2)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that these should not all be required but there's a bug with OIDC and IALMAX: https://cm-jira.usa.gov/browse/LG-6355

)
allow(controller).to receive(:pii_requested_but_locked?).and_return(false)
action

sp_return_log = SpReturnLog.find_by(issuer: client_id)
expect(sp_return_log.ial).to eq(2)
end
end

context 'account is not already verified' do
it 'redirects to the redirect_uri immediately without proofing' do
IdentityLinker.new(user, service_provider).link_identity(ial: 1)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)

action
expect(response).to redirect_to(/^#{params[:redirect_uri]}/)
end

it 'tracks IAL1 authentication event' do
stub_analytics
expect(@analytics).to receive(:track_event).
with(Analytics::OPENID_CONNECT_REQUEST_AUTHORIZATION,
success: true,
client_id: client_id,
errors: {},
unauthorized_scope: false,
user_fully_authenticated: true,
acr_values: 'http://idmanagement.gov/ns/assurance/ial/0',
scope: 'openid profile')
expect(@analytics).to receive(:track_event).
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 0,
billed_ial: 1,
)

IdentityLinker.new(user, service_provider).link_identity(ial: 1)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)
action

sp_return_log = SpReturnLog.find_by(issuer: client_id)
expect(sp_return_log.ial).to eq(1)
end
end

context 'profile is reset' do
let(:user) { create(:profile, :password_reset).user }

it 'redirects to the redirect_uri immediately without proofing' do
IdentityLinker.new(user, service_provider).link_identity(ial: 1)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)

action
expect(response).to redirect_to(/^#{params[:redirect_uri]}/)
end

it 'tracks IAL1 authentication event' do
stub_analytics
expect(@analytics).to receive(:track_event).
with(Analytics::OPENID_CONNECT_REQUEST_AUTHORIZATION,
success: true,
client_id: client_id,
errors: {},
unauthorized_scope: false,
user_fully_authenticated: true,
acr_values: 'http://idmanagement.gov/ns/assurance/ial/0',
scope: 'openid profile')
expect(@analytics).to receive(:track_event).
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 0,
billed_ial: 1,
)

IdentityLinker.new(user, service_provider).link_identity(ial: 1)
user.identities.last.update!(
verified_attributes: %w[given_name family_name birthdate verified_at],
)
action

sp_return_log = SpReturnLog.find_by(issuer: client_id)
expect(sp_return_log.ial).to eq(1)
end
end
end

context 'user has not approved this application' do
it 'redirects verify shared attributes page' do
action
Expand Down
28 changes: 20 additions & 8 deletions spec/controllers/saml_idp_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,11 @@ def name_id_version(format_urn)
idv: false,
finish_profile: false)
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: ial)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: ial,
billed_ial: [ial, 2].min,
)

allow(controller).to receive(:identity_needs_verification?).and_return(false)
saml_get_auth(ial2_settings)
Expand Down Expand Up @@ -707,8 +710,11 @@ def name_id_version(format_urn)
idv: false,
finish_profile: false)
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: 0)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 0,
billed_ial: 2,
)

allow(controller).to receive(:identity_needs_verification?).and_return(false)
saml_get_auth(ialmax_settings)
Expand Down Expand Up @@ -1869,8 +1875,11 @@ def stub_requested_attributes
service_provider: 'http://localhost:3000')
expect(@analytics).to receive(:track_event).with(Analytics::SAML_AUTH, analytics_hash)
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: 1)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 1,
billed_ial: 1,
)

generate_saml_response(user)
end
Expand Down Expand Up @@ -1903,8 +1912,11 @@ def stub_requested_attributes
service_provider: 'http://localhost:3000')
expect(@analytics).to receive(:track_event).with(Analytics::SAML_AUTH, analytics_hash)
expect(@analytics).to receive(:track_event).
with(Analytics::SP_REDIRECT_INITIATED,
ial: 1)
with(
Analytics::SP_REDIRECT_INITIATED,
ial: 1,
billed_ial: 1,
)

generate_saml_response(user)
end
Expand Down
42 changes: 42 additions & 0 deletions spec/forms/openid_connect_authorize_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,48 @@
end
end

describe '#ial' do
context 'when IAL1 passed' do
let(:acr_values) { Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF }

it 'returns 1' do
expect(form.ial).to eq(1)
end
end

context 'when IAL2 passed' do
let(:acr_values) { Saml::Idp::Constants::IAL2_AUTHN_CONTEXT_CLASSREF }

it 'returns 2' do
expect(form.ial).to eq(2)
end
end

context 'when IALMAX passed' do
let(:acr_values) { Saml::Idp::Constants::IALMAX_AUTHN_CONTEXT_CLASSREF }

it 'returns 0' do
expect(form.ial).to eq(0)
end
end

context 'when LOA1 passed' do
let(:acr_values) { Saml::Idp::Constants::LOA1_AUTHN_CONTEXT_CLASSREF }

it 'returns 1' do
expect(form.ial).to eq(1)
end
end

context 'when LOA3 passed' do
let(:acr_values) { Saml::Idp::Constants::LOA3_AUTHN_CONTEXT_CLASSREF }

it 'returns 2' do
expect(form.ial).to eq(2)
end
end
end

describe '#verified_within' do
context 'without a verified_within' do
let(:verified_within) { nil }
Expand Down