Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
9 changes: 9 additions & 0 deletions app/services/idv/steps/ssn_step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def call
return invalid_state_response if invalid_state?

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

if IdentityConfig.store.proofing_device_profiling_collecting_enabled
flow_session[:threatmetrix_session_id] = 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.

Will this overwrite the existing :threatmetrix_session_id (if the user is coming back to edit their SSN)? I think we want to hang on to the original session ID in that case.

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.

It seems like it would, yeah, which we probably want to avoid?

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.

Will we want this to be present in the in-person proofing flow version of the SSN step as well?

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.

That is a very good question, I am not 100% certain, we need to confirm

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.

update: Let's include this on all instances of the SSN page and we can add more specific feature flags if needed

end
end

def extra_view_variables
Expand All @@ -29,6 +33,11 @@ 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
2 changes: 1 addition & 1 deletion app/views/idv/doc_auth/ssn.html.erb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<%= render 'idv/shared/ssn', flow_session: flow_session, success_alert_enabled: !updating_ssn, updating_ssn: updating_ssn %>
<%= render 'idv/shared/ssn', flow_session: flow_session, success_alert_enabled: !updating_ssn, updating_ssn: updating_ssn, threatmetrix_session_id: threatmetrix_session_id %>
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_account_id.empty? || updating_ssn %>
Comment thread
zachmargolis marked this conversation as resolved.
Outdated
<script type="text/javascript" src="https://h.online-metrix.net/fp/tags.js?org_id=<%= IdentityConfig.store.lexisnexis_threatmetrix_account_id %>&session_id=<%= flow_session[:threatmetrix_session_id] %>">
</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_account_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
4 changes: 4 additions & 0 deletions config/initializers/content_security_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
IdentityConfig.store.asset_host.presence,
].compact

if IdentityConfig.store.proofing_device_profiling_collecting_enabled
script_src << 'h.online-metrix.net'
end

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.

After talking with @zachmargolis, I realized that I gave some bad guidance here. Let's not modify CSP in all environments: We want to ensure that we are not making calls to 3rd parties outside of production / staging. Apologies!

Suggested change
if IdentityConfig.store.proofing_device_profiling_collecting_enabled
script_src << 'h.online-metrix.net'
end

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.

We'd still need some CSP revisions for this to work at all, wouldn't we? I would expect some script_src, connect_src, and iframe_src.

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.

That's my understanding as well

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.

I think we'll need the following:

  • script_src
  • connect_src
  • child_src
  • image_src

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.

(I'll leave a followup ticket for CSP stuff)

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.

Out of curiosity, why would image_src be needed? I follow the other ones since we have tags for script/iframe and I presume the script will make calls (therefore connect_src).

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.

ThreatMetrix uses <img> tags as part of its profiling, loading up images sourced from h.online-metrix.net

script_src = [:self, :unsafe_eval] if !Rails.env.production?

style_src = [:self, IdentityConfig.store.asset_host.presence].compact
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_account_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_account_id}&session_id=#{session_id}"
}

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

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

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

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

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

let(:noscript_tag_not_rendered) {
expect(rendered).not_to have_css("noscript iframe[src*='#{js_domain}']", visible: false)
}
Comment thread
zachmargolis marked this conversation as resolved.
Outdated

let(:session_id_input_not_rendered) {
expect(rendered).
not_to have_css('input[name="doc_auth[threatmetrix_session_id]"]', visible: false)
}
Comment thread
zachmargolis marked this conversation as resolved.
Outdated

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_account_id).and_return(lexisnexis_threatmetrix_account_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
script_tag_rendered
end
end

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

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

it 'does not render <script> tag' do
script_tag_not_rendered
end
it 'does not render <noscript> tag' do
noscript_tag_not_rendered
end
end
end

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

it 'does not render <script> tag' do
script_tag_not_rendered
end
it 'does not render <noscript> tag' do
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
script_tag_not_rendered
end
it 'does not render <noscript> tag' do
noscript_tag_not_rendered
end
end
end