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
2 changes: 1 addition & 1 deletion app/controllers/concerns/idv/threat_metrix_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module ThreatMetrixConcern
THREAT_METRIX_WILDCARD_DOMAIN = '*.online-metrix.net'

def override_csp_for_threat_metrix
return unless IdentityConfig.store.proofing_device_profiling_collecting_enabled
return unless FeatureManagement.proofing_device_profiling_collecting_enabled?

return if params[:step] != 'ssn'

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/idv/gpo_verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def confirm_verification_needed
end

def threatmetrix_enabled?
IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify
FeatureManagement.proofing_device_profiling_decisioning_enabled?
end
end
end
7 changes: 2 additions & 5 deletions app/controllers/idv/personal_key_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,8 @@ def pending_profile?
end

def blocked_by_device_profiling?
return false unless IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify
proofing_component = ProofingComponent.find_by(user: current_user)
# pass users who are inbetween feature flag being enabled and have not had a check run.
return false if proofing_component.threatmetrix_review_status.nil?
proofing_component.threatmetrix_review_status != 'pass'
!idv_session.profile.active &&
idv_session.profile.deactivation_reason == 'threatmetrix_review_pending'
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.

Minor update here: Check that the profile is deactivated due to threatmetrix rather than re-evaluating the threatmetrix_review_status

end
end
end
2 changes: 1 addition & 1 deletion app/forms/gpo_verify_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def pending_in_person_enrollment?
end

def threatmetrix_enabled?
IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify
FeatureManagement.proofing_device_profiling_decisioning_enabled?
end

def threatmetrix_check_failed?
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/resolution_proofing_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def proof_lexisnexis_ddp_with_threatmetrix_if_needed(
request_ip:,
timer:
)
return unless IdentityConfig.store.lexisnexis_threatmetrix_enabled
return unless FeatureManagement.proofing_device_profiling_collecting_enabled?

# The API call will fail without a session ID, so do not attempt to make
# it to avoid leaking data when not required.
Expand Down
17 changes: 13 additions & 4 deletions app/services/idv/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,20 @@ def in_person_enrollment?
end

def threatmetrix_failed_and_needs_review?
return unless IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify
return unless IdentityConfig.store.lexisnexis_threatmetrix_enabled
failed_and_needs_review = true
ok_no_review_needed = false

if !FeatureManagement.proofing_device_profiling_decisioning_enabled?
return ok_no_review_needed
end

component = ProofingComponent.find_by(user: @current_user)
return true unless component
!(component.threatmetrix && component.threatmetrix_review_status == 'pass')

return ok_no_review_needed if !component.threatmetrix

return ok_no_review_needed if component.threatmetrix_review_status == 'pass'

return failed_and_needs_review
end
end
end
26 changes: 12 additions & 14 deletions app/views/idv/shared/_ssn.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,19 @@ locals:
<%= new_window_link_to(t('doc_auth.instructions.learn_more'), MarketingSite.security_and_privacy_practices_url) %>
</p>

<% if IdentityConfig.store.proofing_device_profiling_collecting_enabled %>
<% unless IdentityConfig.store.lexisnexis_threatmetrix_org_id.empty? %>
<% if threatmetrix_session_id.present? %>
<% threatmetrix_javascript_urls.each do |threatmetrix_javascript_url| %>
<%= javascript_include_tag threatmetrix_javascript_url, nonce: true %>
<% end %>
<noscript>
<%= content_tag(
:iframe,
'',
src: threatmetrix_iframe_url,
style: 'width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;',
) %>
</noscript>
<% if FeatureManagement.proofing_device_profiling_collecting_enabled? %>
<% if threatmetrix_session_id.present? %>
<% threatmetrix_javascript_urls.each do |threatmetrix_javascript_url| %>
<%= javascript_include_tag threatmetrix_javascript_url, nonce: true %>
<% end %>
<noscript>
<%= content_tag(
:iframe,
'',
src: threatmetrix_iframe_url,
style: 'width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;',
) %>
</noscript>
<% end %>
<% end %>

Expand Down
10 changes: 2 additions & 8 deletions config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,9 @@ lexisnexis_trueid_noliveness_cropping_workflow: customers.gsa2.trueid.workflow
lexisnexis_trueid_noliveness_nocropping_workflow: customers.gsa2.trueid.workflow
###################################################################
# LexisNexis DDP/ThreatMetrix #####################################
lexisnexis_threatmetrix_api_key: test_api_key
lexisnexis_threatmetrix_base_url: https://www.example.com
lexisnexis_threatmetrix_org_id: test_account
lexisnexis_threatmetrix_policy: test-policy
lexisnexis_threatmetrix_mock_enabled: true
lexisnexis_threatmetrix_support_code: ABCD
lexisnexis_threatmetrix_timeout: 1.0
lexisnexis_threatmetrix_enabled: false
lexisnexis_threatmetrix_mock_enabled: true
lexisnexis_threatmetrix_required_to_verify: false
lexisnexis_threatmetrix_js_signing_cert: ''
###################################################################
lockout_period_in_minutes: 10
Expand Down Expand Up @@ -234,7 +228,6 @@ piv_cac_verify_token_url: https://localhost:8443/
platform_auth_set_up_enabled: false
poll_rate_for_verify_in_seconds: 3
proofer_mock_fallback: true
proofing_device_profiling_collecting_enabled: true
proof_address_max_attempts: 5
proof_address_max_attempt_window_in_minutes: 360
proof_ssn_max_attempts: 10
Expand Down Expand Up @@ -445,6 +438,7 @@ production:
kantara_2fa_phone_restricted: false
kantara_2fa_phone_existing_user_restriction: false
kantara_restriction_enforcement_date: '2022-07-19'
lexisnexis_threatmetrix_mock_enabled: false
Copy link
Copy Markdown
Contributor

@theabrad theabrad Jan 12, 2023

Choose a reason for hiding this comment

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

duplicate. line 176 already has mock_enabled: true

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.

Yeah, the goal here is to enable it locally by default but disable it by default in production

logins_per_ip_limit: 20
logins_per_ip_period: 20
logins_per_ip_track_only_mode: true
Expand Down
37 changes: 37 additions & 0 deletions lib/feature_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,41 @@ def self.voip_allowed_phones
allowed_phones.map { |p| Phonelib.parse(p).e164 }.to_set
end
end

# Whether we collect device profiling information as part of the proofing process.
def self.proofing_device_profiling_collecting_enabled?
case IdentityConfig.store.proofing_device_profiling
when :enabled, :collect_only then true
when :disabled then false
# BEGIN temporary transitional fallback
when nil
if IdentityConfig.store.proofing_device_profiling_collecting_enabled.nil?
false
else
IdentityConfig.store.proofing_device_profiling_collecting_enabled
end
# END temporary transitional fallback
else
raise 'Invalid value for proofing_device_profiling'
end
end

# Whether we prevent users from proceeding with identity verification based on the outcomes of
# device profiling.
def self.proofing_device_profiling_decisioning_enabled?
case IdentityConfig.store.proofing_device_profiling
when :enabled then true
when :collect_only, :disabled then false
# BEGIN temporary transitional fallback
when nil
if IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify.nil?
false
else
IdentityConfig.store.lexisnexis_threatmetrix_required_to_verify
end
# END temporary transitional fallback
else
raise 'Invalid value for proofing_device_profiling'
end
end
end
22 changes: 14 additions & 8 deletions lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def add(key, type: :string, allow_nil: false, enum: nil, options: {})

converted_value = CONVERTERS.fetch(type).call(value, options: options) if !value.nil?
raise "#{key} is required but is not present" if converted_value.nil? && !allow_nil
if enum && !enum.include?(converted_value)
if enum && !(enum.include?(converted_value) || (converted_value.nil? && allow_nil))
raise "unexpected #{key}: #{value}, expected one of #{enum}"
end

Expand Down Expand Up @@ -248,13 +248,13 @@ def self.build_store(config_map)
config.add(:lexisnexis_trueid_noliveness_cropping_workflow, type: :string)
config.add(:lexisnexis_trueid_noliveness_nocropping_workflow, type: :string)
config.add(:lexisnexis_trueid_timeout, type: :float)
config.add(:lexisnexis_threatmetrix_api_key, type: :string)
config.add(:lexisnexis_threatmetrix_base_url, type: :string)
config.add(:lexisnexis_threatmetrix_enabled, type: :boolean)
config.add(:lexisnexis_threatmetrix_api_key, type: :string, allow_nil: true)
config.add(:lexisnexis_threatmetrix_base_url, type: :string, allow_nil: true)
config.add(:lexisnexis_threatmetrix_enabled, type: :boolean, allow_nil: true)
config.add(:lexisnexis_threatmetrix_mock_enabled, type: :boolean)
config.add(:lexisnexis_threatmetrix_org_id, type: :string)
config.add(:lexisnexis_threatmetrix_policy, type: :string)
config.add(:lexisnexis_threatmetrix_required_to_verify, type: :boolean)
config.add(:lexisnexis_threatmetrix_org_id, type: :string, allow_nil: true)
config.add(:lexisnexis_threatmetrix_policy, type: :string, allow_nil: true)
config.add(:lexisnexis_threatmetrix_required_to_verify, type: :boolean, allow_nil: true)
config.add(:lexisnexis_threatmetrix_support_code, type: :string)
config.add(:lexisnexis_threatmetrix_timeout, type: :float)
config.add(:lexisnexis_threatmetrix_js_signing_cert, type: :string)
Expand Down Expand Up @@ -323,7 +323,13 @@ def self.build_store(config_map)
config.add(:platform_auth_set_up_enabled, type: :boolean)
config.add(:poll_rate_for_verify_in_seconds, type: :integer)
config.add(:proofer_mock_fallback, type: :boolean)
config.add(:proofing_device_profiling_collecting_enabled, type: :boolean)
config.add(
:proofing_device_profiling,
type: :symbol,
enum: [:disabled, :collect_only, :enabled],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

adding :collect_only is a great use of an enum!

allow_nil: true,
)
config.add(:proofing_device_profiling_collecting_enabled, type: :boolean, allow_nil: true)
config.add(:proof_address_max_attempts, type: :integer)
config.add(:proof_address_max_attempt_window_in_minutes, type: :integer)
config.add(:proof_ssn_max_attempts, type: :integer)
Expand Down
4 changes: 2 additions & 2 deletions spec/controllers/concerns/idv/threat_metrix_concern_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def index; end
let(:ff_enabled) { true }

before do
allow(IdentityConfig.store).to receive(:proofing_device_profiling_collecting_enabled).
and_return(ff_enabled)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).
and_return(ff_enabled ? :enabled : :disabled)
end

context 'ff is set' do
Expand Down
6 changes: 2 additions & 4 deletions spec/controllers/idv/gpo_verify_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@
allow(decorated_user).to receive(:pending_profile_requires_verification?).
and_return(has_pending_profile)

allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).
and_return(threatmetrix_enabled)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(threatmetrix_enabled)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).
and_return(threatmetrix_enabled ? :enabled : :disabled)
end

describe '#index' do
Expand Down
4 changes: 2 additions & 2 deletions spec/controllers/idv/personal_key_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,7 @@ def index
context 'with device profiling decisioning enabled' do
before do
ProofingComponent.create(user: user, threatmetrix: true, threatmetrix_review_status: nil)
allow(IdentityConfig.store).
to receive(:lexisnexis_threatmetrix_required_to_verify).and_return(true)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
end

context 'threatmetrix review status is nil' do
Expand Down Expand Up @@ -282,6 +281,7 @@ def index
context 'device profiling fails' do
before do
ProofingComponent.find_by(user: user).update(threatmetrix_review_status: 'reject')
profile.active = false
profile.deactivation_reason = :threatmetrix_review_pending
end

Expand Down
5 changes: 1 addition & 4 deletions spec/controllers/idv/review_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,7 @@ def show
threatmetrix: true,
threatmetrix_review_status: 'review',
)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).
and_return(true)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(true)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
end

it 'creates a disabled profile' do
Expand Down
3 changes: 3 additions & 0 deletions spec/features/idv/doc_auth/ssn_step_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
include DocCaptureHelper

before do
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_org_id).and_return('test_org')

sign_in_and_2fa_user
complete_doc_auth_steps_before_ssn_step
end
Expand Down
5 changes: 2 additions & 3 deletions spec/features/idv/in_person_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
let(:user) { user_with_2fa }

before do
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).and_return(true)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(true)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_org_id).and_return('test_org')
end

it 'allows the user to continue down the happy path', allow_browser_log: true do
Expand Down
24 changes: 8 additions & 16 deletions spec/features/idv/steps/gpo_otp_verification_step_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,26 @@
end
let(:user) { profile.user }
let(:threatmetrix_enabled) { false }
let(:threatmetrix_required_to_verify) { false }
let(:threatmetrix_review_status) { nil }
let(:redirect_after_verification) { nil }
let(:profile_should_be_active) { true }
let(:expected_deactivation_reason) { nil }

before do
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).
and_return(threatmetrix_enabled)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(threatmetrix_required_to_verify)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).
and_return(threatmetrix_enabled ? :enabled : :disabled)
end

it_behaves_like 'gpo otp verification'

context 'ThreatMetrix disabled, but we have ThreatMetrix status on proofing component' do
let(:threatmetrix_enabled) { false }
let(:threatmetrix_review_status) { 'review' }
it_behaves_like 'gpo otp verification'
end

context 'ThreatMetrix enabled' do
let(:threatmetrix_enabled) { true }
let(:threatmetrix_required_to_verify) { true }

context 'ThreatMetrix says "pass"' do
let(:threatmetrix_review_status) { 'pass' }
Expand All @@ -68,16 +70,6 @@
let(:threatmetrix_review_status) { nil }
it_behaves_like 'gpo otp verification'
end

context 'without verification requirement enabled creates active profile' do
let(:threatmetrix_required_to_verify) { false }

let(:threatmetrix_review_status) { 'review' }
let(:redirect_after_verification) { account_path } # TODO
let(:profile_should_be_active) { true }
let(:expected_deactivation_reason) { nil }
it_behaves_like 'gpo otp verification'
end
end

context 'with gpo feature disabled' do
Expand Down
5 changes: 2 additions & 3 deletions spec/features/idv/threatmetrix_pending_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
include IdvStepHelper

before do
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).and_return(true)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(true)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_org_id).and_return('test_org')
end

scenario 'users pending threatmetrix see sad face screen and cannot perform idv' do
Expand Down
8 changes: 2 additions & 6 deletions spec/forms/gpo_verify_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,7 @@
let(:threatmetrix_review_status) { 'reject' }

before do
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_enabled).
and_return(true)
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(true)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:enabled)
end

it 'returns true' do
Expand All @@ -184,8 +181,7 @@

context 'threatmetrix is not required for verification' do
before do
allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_required_to_verify).
and_return(false)
allow(IdentityConfig.store).to receive(:proofing_device_profiling).and_return(:disabled)
end

it 'returns true' do
Expand Down
Loading