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
3 changes: 3 additions & 0 deletions app/decorators/service_provider_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def mfa_expiration_interval
end

def requested_more_recent_verification?
unless IdentityConfig.store.allowed_verified_within_providers.include?(sp_issuer)
return false
end
return false if authorize_form.verified_within.blank?

verified_at = view_context.current_user.active_profile&.verified_at
Expand Down
14 changes: 10 additions & 4 deletions app/forms/openid_connect_authorize_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class OpenidConnectAuthorizeForm
validate :validate_unauthorized_scope
validate :validate_privileges
validate :validate_prompt
validate :validate_verified_within_format
validate :validate_verified_within_duration
validate :validate_verified_within_format, if: :verified_within_allowed?
validate :validate_verified_within_duration, if: :verified_within_allowed?

def initialize(params)
@acr_values = parse_to_values(params[:acr_values], Saml::Idp::Constants::VALID_AUTHN_CONTEXTS)
Expand All @@ -56,8 +56,10 @@ def initialize(params)
@scope = parse_to_values(params[:scope], scopes)
@unauthorized_scope = check_for_unauthorized_scope(params)

@duration_parser = DurationParser.new(params[:verified_within])
@verified_within = @duration_parser.parse
if verified_within_allowed?
@duration_parser = DurationParser.new(params[:verified_within])
@verified_within = @duration_parser.parse
end
end

def submit
Expand Down Expand Up @@ -274,4 +276,8 @@ def validate_privileges
def highest_level_aal(aal_values)
AALS_BY_PRIORITY.find { |aal| aal_values.include?(aal) }
end

def verified_within_allowed?
IdentityConfig.store.allowed_verified_within_providers.include?(client_id)
end
end
1 change: 1 addition & 0 deletions config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ aamva_verification_request_timeout: 5.0
aamva_verification_url: https://example.org:12345/verification/url
all_redirect_uris_cache_duration_minutes: 2
allowed_ialmax_providers: '[]'
allowed_verified_within_providers: '[]'
account_reset_token_valid_for_days: 1
account_reset_wait_period_days: 1
account_suspended_support_code: EFGHI
Expand Down
1 change: 1 addition & 0 deletions lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def self.build_store(config_map)
config.add(:address_identity_proofing_supported_country_codes, type: :json)
config.add(:all_redirect_uris_cache_duration_minutes, type: :integer)
config.add(:allowed_ialmax_providers, type: :json)
config.add(:allowed_verified_within_providers, type: :json)
config.add(:asset_host, type: :string)
config.add(:async_stale_job_timeout_seconds, type: :integer)
config.add(:async_wait_timeout_seconds, type: :integer)
Expand Down
68 changes: 50 additions & 18 deletions spec/decorators/service_provider_session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,45 +224,77 @@
describe '#requested_more_recent_verification?' do
let(:verified_within) { nil }
let(:user) { create(:user) }
let(:client_id) { sp.issuer }

before do
allow(view_context).to receive(:current_user).and_return(user)
allow(IdentityConfig.store).to receive(
:allowed_verified_within_providers,
) { [client_id] }
allow(session_decorator).to receive(:authorize_form).
and_return(OpenidConnectAuthorizeForm.new(verified_within: verified_within))
and_return(OpenidConnectAuthorizeForm.new(verified_within:, client_id:))
end

subject(:requested_more_recent_verification?) do
session_decorator.requested_more_recent_verification?
end

it 'is false with no verified_within param' do
expect(requested_more_recent_verification?).to eq(false)
context 'issuer is allowed to use verified_within' do
it 'is false with no verified_within param' do
expect(requested_more_recent_verification?).to eq(false)
end

context 'with a valid verified_within' do
let(:verified_within) { '45d' }

it 'is true if the user does not have an activated profile' do
expect(requested_more_recent_verification?).to eq(true)
end

context 'the verified_at is newer than the verified_within ' do
before do
create(:profile, :active, user: user, verified_at: 15.days.ago)
end

it 'is false' do
expect(requested_more_recent_verification?).to eq(false)
end
end

context 'the verified_at is older than the verified_at' do
before do
create(:profile, :active, user: user, verified_at: 60.days.ago)
end

it 'is true' do
expect(requested_more_recent_verification?).to eq(true)
end
end
end
end

context 'with a valid verified_within' do
let(:verified_within) { '45d' }
context 'issuer is not allowed to use verified_within' do
let(:client_id) { 'different id' }

it 'is true if the user does not have an activated profile' do
expect(requested_more_recent_verification?).to eq(true)
it 'is false with no verified_within param' do
expect(requested_more_recent_verification?).to eq(false)
end

context 'the verified_at is newer than the verified_within ' do
before do
create(:profile, :active, user: user, verified_at: 15.days.ago)
end
context 'with a valid verified_within' do
let(:verified_within) { '45d' }

it 'is false' do
expect(requested_more_recent_verification?).to eq(false)
end
end

context 'the verified_at is older than the verified_at' do
before do
create(:profile, :active, user: user, verified_at: 60.days.ago)
end
context 'the verified_at is older than the verified_at' do
before do
create(:profile, :active, user: user, verified_at: 60.days.ago)
end

it 'is true' do
expect(requested_more_recent_verification?).to eq(true)
it 'is false' do
expect(requested_more_recent_verification?).to eq(false)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions spec/features/openid_connect/openid_connect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@

it 'errors if verified_within param is too recent', driver: :mobile_rack_test do
client_id = 'urn:gov:gsa:openidconnect:test'
allow(IdentityConfig.store).to receive(:allowed_verified_within_providers).
and_return([client_id])
state = SecureRandom.hex
nonce = SecureRandom.hex
code_verifier = SecureRandom.hex
Expand Down Expand Up @@ -534,6 +536,9 @@

it 'sends the user through idv again via verified_within param', js: true do
client_id = 'urn:gov:gsa:openidconnect:sp:server'
allow(IdentityConfig.store).to receive(:allowed_verified_within_providers).
and_return([client_id])

user = user_with_2fa
_profile = create(
:profile, :active,
Expand Down
5 changes: 5 additions & 0 deletions spec/features/sp_cost_tracking_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
let(:email) { 'test@test.com' }
let(:password) { Features::SessionHelper::VALID_PASSWORD }

before do
allow(IdentityConfig.store).to receive(:allowed_verified_within_providers).
and_return([issuer])
end

it 'logs the correct costs for an ial2 user creation from sp with oidc', js: true do
create_ial2_user_from_sp(email)

Expand Down
100 changes: 77 additions & 23 deletions spec/forms/openid_connect_authorize_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -554,36 +554,90 @@
end

describe '#verified_within' do
context 'without a verified_within' do
let(:verified_within) { nil }
it 'is valid' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to eq(nil)
context 'the issuer is allowed to use verified_within' do
before do
allow(IdentityConfig.store).to receive(:allowed_verified_within_providers).
and_return([client_id])
end
end

context 'with a duration that is too short (<30 days)' do
let(:verified_within) { '2d' }
it 'has errors' do
expect(form.valid?).to eq(false)
expect(form.errors[:verified_within]).
to eq(['value must be at least 30 days or older'])
context 'without a verified_within' do
let(:verified_within) { nil }

it 'is valid' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to eq(nil)
end
end
end

context 'with a format in days' do
let(:verified_within) { '45d' }
it 'parses the value as a number of days' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to eq(45.days)
context 'with a duration that is too short (<30 days)' do
let(:verified_within) { '2d' }

it 'has errors' do
expect(form.valid?).to eq(false)
expect(form.errors[:verified_within]).
to eq(['value must be at least 30 days or older'])
end
end

context 'with a format in days' do
let(:verified_within) { '45d' }

it 'parses the value as a number of days' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to eq(45.days)
end
end

context 'with a verified_within with a bad format' do
let(:verified_within) { 'bbb' }

it 'has errors' do
expect(form.valid?).to eq(false)
expect(form.errors[:verified_within]).to eq(['Unrecognized format for verified_within'])
end
end
end

context 'with a verified_within with a bad format' do
let(:verified_within) { 'bbb' }
it 'has errors' do
expect(form.valid?).to eq(false)
expect(form.errors[:verified_within]).to eq(['Unrecognized format for verified_within'])
context 'the issuer is not allowed to use verified_within' do
before do
allow(IdentityConfig.store).to receive(:allowed_verified_within_providers).
and_return([])
end

context 'without a verified_within' do
let(:verified_within) { nil }

it 'verified_within is not set' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to be nil
end
end

context 'with a duration that is too short (<30 days)' do
let(:verified_within) { '2d' }

it 'verified_within is not set' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to be nil
end
end

context 'with a format in days' do
let(:verified_within) { '45d' }

it 'verified_within is not set' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to be nil
end
end

context 'with a verified_within with a bad format' do
let(:verified_within) { 'bbb' }

it 'verified_within is not set' do
expect(form.valid?).to eq(true)
expect(form.verified_within).to be nil
end
end
end
end
Expand Down