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
10 changes: 10 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ def analytics_exception_info(exception)
}
end

def add_sp_cost(token)
Db::SpCost::AddSpCost.call(
current_sp,
sp_session_ial,
token,
transaction_id: nil,
user: current_user,
)
end

def mobile?
BrowserCache.parse(request.user_agent).mobile?
end
Expand Down
1 change: 1 addition & 0 deletions app/controllers/concerns/billable_event_trackable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def track_billing_events
increment_sp_monthly_auths
create_sp_return_log(billable: true)
mark_current_session_billed
add_sp_cost(:authentication)
end
end

Expand Down
1 change: 1 addition & 0 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def process_locked_out_user
def handle_valid_authentication
sign_in(resource_name, resource)
cache_active_profile(auth_params[:password])
add_sp_cost(:digest)
create_user_event(:sign_in_before_2fa)
EmailAddress.update_last_sign_in_at_on_user_id_and_email(
user_id: current_user.id,
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/users/two_factor_authentication_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def handle_valid_otp_params(method, default = nil)
end

def handle_telephony_result(method:, default:)
track_events
track_events(method)
if @telephony_result.success?
redirect_to login_two_factor_url(
otp_delivery_preference: method,
Expand All @@ -189,8 +189,9 @@ def handle_telephony_result(method:, default:)
end
end

def track_events
def track_events(method)
analytics.track_event(Analytics::TELEPHONY_OTP_SENT, @telephony_result.to_h)
add_sp_cost(method) if @telephony_result.success?
end

def exceeded_otp_send_limit?
Expand Down
6 changes: 6 additions & 0 deletions app/services/db/sp_cost/add_sp_cost.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ class SpCostTypeError < StandardError; end
acuant_back_image
acuant_result
acuant_selfie
authentication
digest
lexis_nexis_resolution
lexis_nexis_address
gpo_letter
phone_otp
sms
user_added
voice
].freeze

def self.call(service_provider, ial, token, transaction_id: nil, user: nil)
Expand Down
1 change: 1 addition & 0 deletions app/services/identity_linker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def identity
def find_or_create_identity_with_costing
identity_record = identity_relation.first
return identity_record if identity_record
Db::SpCost::AddSpCost.call(service_provider, @ial, :user_added)
user.identities.create(service_provider: service_provider.issuer)
end

Expand Down
1 change: 1 addition & 0 deletions app/services/idv/send_phone_confirmation_otp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def otp_sent_response

def add_cost
Db::ProofingCost::AddUserProofingCost.call(user.id, :phone_otp)
Db::SpCost::AddSpCost.call(idv_session.service_provider, 2, :phone_otp)
end

def extra_analytics_attributes
Expand Down
12 changes: 12 additions & 0 deletions spec/controllers/saml_idp_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,8 @@ def stub_requested_attributes
ial: 1)

generate_saml_response(user)

expect_sp_authentication_cost
end
end

Expand Down Expand Up @@ -1787,6 +1789,8 @@ def stub_requested_attributes
ial: 1)

generate_saml_response(user)

expect_sp_authentication_cost
end
end
end
Expand All @@ -1813,4 +1817,12 @@ def stub_requested_attributes
expect(subject.external_saml_request?).to eq false
end
end

def expect_sp_authentication_cost
sp_cost = SpCost.where(
issuer: 'http://localhost:3000',
cost_type: 'authentication',
).first
expect(sp_cost).to be_present
end
end
80 changes: 74 additions & 6 deletions spec/features/sp_cost_tracking_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,32 @@
let(:email) { 'test@test.com' }
let(:password) { Features::SessionHelper::VALID_PASSWORD }

it 'logs the correct costs for an ial1 user creation from sp with oidc' do
create_ial1_user_from_sp(email)

expect_sp_cost_type(0, 1, 'sms')
expect_sp_cost_type(1, 1, 'user_added')
expect_sp_cost_type(2, 1, 'authentication')
end

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

expect_sp_cost_type(0, 2, 'acuant_front_image')
expect_sp_cost_type(1, 2, 'acuant_back_image')
expect_sp_cost_type(2, 2, 'acuant_result')
expect_sp_cost_type(0, 2, 'sms')
expect_sp_cost_type(1, 2, 'acuant_front_image')
expect_sp_cost_type(2, 2, 'acuant_back_image')
expect_sp_cost_type(3, 2, 'acuant_result')
expect_sp_cost_type(
3, 2, 'lexis_nexis_resolution',
4, 2, 'lexis_nexis_resolution',
transaction_id: Proofing::Mock::ResolutionMockClient::TRANSACTION_ID
)
expect_sp_cost_type(
4, 2, 'aamva',
5, 2, 'aamva',
transaction_id: Proofing::Mock::StateIdMockClient::TRANSACTION_ID
)
expect_sp_cost_type(5, 2, 'lexis_nexis_address')
expect_sp_cost_type(6, 2, 'lexis_nexis_address')
expect_sp_cost_type(7, 2, 'user_added')
expect_sp_cost_type(8, 2, 'authentication')
end

it 'logs the cost to the SP for reproofing' do
Expand Down Expand Up @@ -65,6 +76,56 @@
end
end

it 'logs the correct costs for an ial1 authentication' do
create_ial1_user_from_sp(email)
SpCost.delete_all

# track costs without dealing with 'remember device'
Capybara.reset_session!

visit_idp_from_sp_with_ial1(:oidc)
fill_in_credentials_and_submit(email, password)
fill_in_code_with_last_phone_otp
click_submit_default

expect_sp_cost_type(0, 1, 'digest')
expect_sp_cost_type(1, 1, 'sms')
expect_sp_cost_type(2, 1, 'authentication')
end

it 'logs the correct costs for an ial2 authentication' do
create_ial2_user_from_sp(email)
SpCost.delete_all

# track costs without dealing with 'remember device'
Capybara.reset_session!

visit_idp_from_sp_with_ial2(:oidc)
fill_in_credentials_and_submit(email, password)
fill_in_code_with_last_phone_otp
click_submit_default

expect_sp_cost_type(0, 2, 'digest')
expect_sp_cost_type(1, 2, 'sms')
expect_sp_cost_type(2, 2, 'authentication')
end

it 'logs the correct costs for a direct authentication' do
visit root_path
create_ial1_user_directly(email)
SpCost.delete_all

# track costs without dealing with 'remember device'
Capybara.reset_session!

visit root_path
fill_in_credentials_and_submit(email, password)
fill_in_code_with_last_phone_otp
click_submit_default

expect_direct_cost_type(0, 'digest')
end

def expect_sp_cost_type(sp_cost_index, ial, token, transaction_id: nil)
sp_cost = sp_costs(sp_cost_index)
expect(sp_cost.ial).to eq(ial)
Expand All @@ -74,6 +135,13 @@ def expect_sp_cost_type(sp_cost_index, ial, token, transaction_id: nil)
expect(sp_cost.transaction_id).to(eq(transaction_id)) if transaction_id
end

def expect_direct_cost_type(sp_cost_index, token)
sp_cost = sp_costs(sp_cost_index)
expect(sp_cost.issuer).to eq('')
expect(sp_cost.agency_id).to eq(0)
expect(sp_cost.cost_type).to eq(token)
end

def sp_costs(index)
SpCost.order('id asc')[index]
end
Expand Down