Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
719b9a1
added threatmetrix domain to CSP
theabrad Jul 28, 2022
84ddc25
added script and noscript for device profiling
theabrad Aug 1, 2022
01ebbda
Add speculative tests for ThreatMetrix integration
matthinz Aug 2, 2022
2908bc7
Added session_id to ssn page
theabrad Aug 3, 2022
ddd0ef0
Update ThreatMetrix JS include tests
matthinz Aug 3, 2022
227a018
Fix linting errors. Make tests pass
theabrad Aug 4, 2022
e20904d
moved around logic for checking if TM org_id is available
theabrad Aug 4, 2022
1b6047b
update changelog
theabrad Aug 4, 2022
32a885b
added feature flags on csp and threatmetrix session id
theabrad Aug 4, 2022
10ecc4e
move threatmetrix_session_id into flow session
theabrad Aug 4, 2022
82ee43c
fixup
theabrad Aug 5, 2022
aec8ab8
Update config/initializers/content_security_policy.rb
theabrad Aug 5, 2022
a14ee08
changed lexisnexis_account_id to org_id
theabrad Aug 8, 2022
7060439
moved test expectations into methods
theabrad Aug 8, 2022
75516f4
add threatmetrix_session_id to ipp flow
theabrad Aug 9, 2022
b6f5357
Merge branch 'main' of github.com:18F/identity-idp into lg-7014-devic…
theabrad Aug 9, 2022
0272f7c
Merge branch 'lg-7014-device-profiling-ssn' of github.com:18F/identit…
theabrad Aug 9, 2022
b2bf717
dont create a new session id if updating_ssn
theabrad Aug 9, 2022
c940d22
fixup
theabrad Aug 9, 2022
0f6ebc5
changed function to generate_threatmetrix_session_id
theabrad Aug 10, 2022
d09f775
add tests for ssn_step
theabrad Aug 10, 2022
13b089e
tests for ipp ssn_step
theabrad Aug 11, 2022
5ced292
fixed logic and tests
theabrad Aug 11, 2022
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
14 changes: 13 additions & 1 deletion app/services/idv/steps/ipp/ssn_step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ class SsnStep < DocAuthBaseStep

def call
flow_session[:pii_from_user][:ssn] = flow_params[:ssn]

flow_session[:threatmetrix_session_id] = threatmetrix_session_id unless updating_ssn

idv_session.delete('applicant')
end

def extra_view_variables
{
updating_ssn: flow_session[:pii_from_user][:ssn].present?,
updating_ssn: updating_ssn,
}
end

Expand All @@ -20,6 +23,15 @@ def extra_view_variables
def form_submit
Idv::SsnFormatForm.new(current_user).submit(permit(:ssn))
end

def updating_ssn
flow_session.dig(:pii_from_user, :ssn).present?
end

def threatmetrix_session_id
Comment thread
zachmargolis marked this conversation as resolved.
Outdated
return unless IdentityConfig.store.proofing_device_profiling_collecting_enabled
SecureRandom.uuid
end
end
end
end
Expand Down
14 changes: 13 additions & 1 deletion app/services/idv/steps/ssn_step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ def call
return invalid_state_response if invalid_state?

flow_session[:pii_from_doc][:ssn] = flow_params[:ssn]

flow_session[:threatmetrix_session_id] = threatmetrix_session_id unless updating_ssn

idv_session.delete('applicant')
end

def extra_view_variables
{
updating_ssn: flow_session.dig(:pii_from_doc, :ssn).present?,
updating_ssn: updating_ssn,
}
end

Expand All @@ -26,10 +29,19 @@ def invalid_state?
flow_session[:pii_from_doc].nil?
end

def updating_ssn

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.

let's file a FIXME ticket and see if we can find a way to share code with these two SSN steps? In case we ever add a 3rd?

flow_session.dig(:pii_from_doc, :ssn).present?
end

def invalid_state_response
mark_step_incomplete(:document_capture)
FormResponse.new(success: false)
end

def threatmetrix_session_id
return nil if !IdentityConfig.store.proofing_device_profiling_collecting_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.

Same as above, do we need to check IdentityConfig.store.proofing_device_profiling_collecting_enabled twice (here and in the call function)?

SecureRandom.uuid
end
end
end
end
11 changes: 11 additions & 0 deletions app/views/idv/shared/_ssn.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ 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? || updating_ssn %>
<script type="text/javascript" src="https://h.online-metrix.net/fp/tags.js?org_id=<%= IdentityConfig.store.lexisnexis_threatmetrix_org_id %>&session_id=<%= flow_session[:threatmetrix_session_id] %>">

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.

Questions, maybe we can address in a follow-up PR later, but:

  • Do we need to worry about adding a nonce to this <script> tag so our CSP will allow it in prod? ex
  • What if we used our URIService.add_params helper so we don't have to manually interpolate?
Suggested change
<script type="text/javascript" src="https://h.online-metrix.net/fp/tags.js?org_id=<%= IdentityConfig.store.lexisnexis_threatmetrix_org_id %>&session_id=<%= flow_session[:threatmetrix_session_id] %>">
<script type="text/javascript" src="<%= URIService.add_params("https://h.online-metrix.net/fp/tags.js", org_id: IdentityConfig.store.lexisnexis_threatmetrix_org_id, session_id: flow_session[:threatmetrix_session_id]) %>">

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.

Another thought, we may want to turn the domain into a config value but that's not needed right now

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.

I'll create a follow up ticket for these.

</script>
<noscript>
<iframe style="width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;" src="https://h.online-metrix.net/fp/tags?org_id=<%= IdentityConfig.store.lexisnexis_threatmetrix_org_id %>&session_id=<%= flow_session[:threatmetrix_session_id] %>">
</iframe>
</noscript>
<% end %>
<% end %>

<% if IdentityConfig.store.proofer_mock_fallback %>
<div class="usa-alert usa-alert--info margin-bottom-4" role="status">
<div class="usa-alert__body">
Expand Down
2 changes: 1 addition & 1 deletion config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ lexisnexis_trueid_noliveness_nocropping_workflow: customers.gsa.trueid.workflow
# LexisNexis ThreatMetrix ##########################################
lexisnexis_threatmetrix_base_url: https://www.example.com
lexisnexis_threatmetrix_request_mode: testing
lexisnexis_threatmetrix_account_id: test_account
lexisnexis_threatmetrix_org_id: test_account
lexisnexis_threatmetrix_username: test_username
lexisnexis_threatmetrix_password: test_password
lexisnexis_threatmetrix_instant_verify_timeout: 1.0
Expand Down
2 changes: 1 addition & 1 deletion lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def self.build_store(config_map)
config.add(:lexisnexis_trueid_timeout, type: :float)
config.add(:lexisnexis_threatmetrix_base_url, type: :string)
config.add(:lexisnexis_threatmetrix_request_mode, type: :string)
config.add(:lexisnexis_threatmetrix_account_id, type: :string)
config.add(:lexisnexis_threatmetrix_org_id, type: :string)
config.add(:lexisnexis_threatmetrix_username, type: :string)
config.add(:lexisnexis_threatmetrix_password, type: :string)
config.add(:lexisnexis_threatmetrix_instant_verify_timeout, type: :float)
Expand Down
119 changes: 119 additions & 0 deletions spec/views/idv/shared/_ssn.html.erb_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require 'rails_helper'

describe 'idv/shared/_ssn.html.erb' do
include Devise::Test::ControllerHelpers

let(:proofing_device_profiling_collecting_enabled) { nil }
let(:lexisnexis_threatmetrix_org_id) { 'test_org_id' }
let(:session_id) { 'ABCD-1234' }
let(:updating_ssn) { false }
let(:js_domain) { 'h.online-metrix.net' }

let(:tags_js_url) {
"https://#{js_domain}/fp/tags.js?org_id=#{lexisnexis_threatmetrix_org_id}&session_id=#{session_id}"
}

let(:tags_iframe_url) {
"https://#{js_domain}/fp/tags?org_id=#{lexisnexis_threatmetrix_org_id}&session_id=#{session_id}"
}

before :each do
allow(view).to receive(:url_for).and_return('https://example.com/')

allow(IdentityConfig.store).
to receive(:proofing_device_profiling_collecting_enabled).
and_return(proofing_device_profiling_collecting_enabled)
allow(IdentityConfig.store).
to receive(:lexisnexis_threatmetrix_org_id).and_return(lexisnexis_threatmetrix_org_id)

render partial: 'idv/shared/ssn', locals: {
flow_session: {
threatmetrix_session_id: session_id,
},
success_alert_enabled: false,
updating_ssn: updating_ssn,
}
end

context 'when threatmetrix collection enabled' do
let(:proofing_device_profiling_collecting_enabled) { true }

context 'and org id specified' do
context 'and entering ssn for the first time' do
describe '<script> tag' do
it 'is rendered' do
expect_script_tag_rendered
end
end

describe '<noscript> tag' do
it 'is rendered' do
expect_noscript_tag_rendered
end
end
end

context 'updating ssn already entered' do
let(:updating_ssn) { true }

it 'does not render <script> tag' do
expect_script_tag_not_rendered
end
it 'does not render <noscript> tag' do
expect_noscript_tag_not_rendered
end
end
end

context 'org id not specified' do
let(:lexisnexis_threatmetrix_org_id) { '' }

it 'does not render <script> tag' do
expect_script_tag_not_rendered
end
it 'does not render <noscript> tag' do
expect_noscript_tag_not_rendered
end
end
end

context 'threatmetrix collection disabled' do
let(:proofing_device_profiling_collecting_enabled) { false }

it 'does not render <script> tag' do
expect_script_tag_not_rendered
end
it 'does not render <noscript> tag' do
expect_noscript_tag_not_rendered
end
end

def expect_script_tag_rendered
expect(rendered).to have_css("script[src='#{tags_js_url}']", visible: false)
end

def expect_noscript_tag_rendered
expect(rendered).to have_css("noscript iframe[src='#{tags_iframe_url}']", visible: false)
end

def expect_session_id_input_rendered
expect(rendered).
to have_css(
"input[type=hidden][name='doc_auth[threatmetrix_session_id]'][value='#{session_id}']",
visible: false,
)
end

def expect_script_tag_not_rendered
expect(rendered).not_to have_css("script[src*='#{js_domain}']", visible: false)
end

def expect_noscript_tag_not_rendered
expect(rendered).not_to have_css("noscript iframe[src*='#{js_domain}']", visible: false)
end

def expect_session_id_input_not_rendered
expect(rendered).
not_to have_css('input[name="doc_auth[threatmetrix_session_id]"]', visible: false)
end
end