Skip to content

Commit

Permalink
Merge pull request #11188 from 18F/stages/rc-2024-09-03
Browse files Browse the repository at this point in the history
Deploy RC 411 to Production
  • Loading branch information
jmdembe authored Sep 3, 2024
2 parents aca59a5 + e82d6c9 commit d74df5a
Show file tree
Hide file tree
Showing 50 changed files with 1,258 additions and 202 deletions.
4 changes: 2 additions & 2 deletions app/controllers/concerns/ab_testing_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ module AbTestingConcern
# @param [Symbol] test Name of the test, which should correspond to an A/B test defined in
# # config/initializer/ab_tests.rb.
# @return [Symbol,nil] Bucket to use for the given test, or nil if the test is not active.
def ab_test_bucket(test_name)
def ab_test_bucket(test_name, user: current_user)
test = AbTests.all[test_name]
raise "Unknown A/B test: #{test_name}" unless test

test.bucket(
request:,
service_provider: current_sp&.issuer,
session:,
user: current_user,
user:,
user_session:,
)
end
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/idv/enter_password_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def create
gpo_verification_pending: idv_session.profile.gpo_verification_pending?,
in_person_verification_pending: idv_session.profile.in_person_verification_pending?,
deactivation_reason: idv_session.profile.deactivation_reason,
proofing_workflow_time_in_seconds: idv_session.proofing_workflow_time_in_seconds,
**ab_test_analytics_buckets,
)
Funnel::DocAuth::RegisterStep.new(current_user.id, current_sp&.issuer).
Expand All @@ -62,6 +63,7 @@ def create
gpo_verification_pending: idv_session.profile.gpo_verification_pending?,
in_person_verification_pending: idv_session.profile.in_person_verification_pending?,
deactivation_reason: idv_session.profile.deactivation_reason,
proofing_workflow_time_in_seconds: idv_session.proofing_workflow_time_in_seconds,
**ab_test_analytics_buckets,
)

Expand Down
1 change: 1 addition & 0 deletions app/controllers/idv/welcome_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class WelcomeController < ApplicationController
before_action :confirm_not_rate_limited

def show
idv_session.proofing_started_at ||= Time.zone.now.iso8601
analytics.idv_doc_auth_welcome_visited(**analytics_arguments)

Funnel::DocAuth::RegisterStep.new(current_user.id, sp_session[:issuer]).
Expand Down
33 changes: 26 additions & 7 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class SessionsController < Devise::SessionsController
include Api::CsrfTokenConcern
include ForcedReauthenticationConcern
include NewDeviceConcern
include AbTestingConcern

rescue_from ActionController::InvalidAuthenticityToken, with: :redirect_to_signin

Expand Down Expand Up @@ -41,7 +42,7 @@ def create
handle_valid_authentication
ensure
handle_invalid_authentication if rate_limit_password_failure && !current_user
track_authentication_attempt(auth_params[:email])
track_authentication_attempt
end

def destroy
Expand Down Expand Up @@ -97,13 +98,24 @@ def locked_out_time_remaining

def valid_captcha_result?
return @valid_captcha_result if defined?(@valid_captcha_result)
@valid_captcha_result = SignInRecaptchaForm.new(**recaptcha_form_args).submit(
email: auth_params[:email],
@valid_captcha_result = recaptcha_form.submit(
recaptcha_token: params.require(:user)[:recaptcha_token],
device_cookie: cookies[:device],
).success?
end

def recaptcha_form
@recaptcha_form ||= SignInRecaptchaForm.new(
email: auth_params[:email],
device_cookie: cookies[:device],
ab_test_bucket: ab_test_bucket(:RECAPTCHA_SIGN_IN, user: user_from_params),
**recaptcha_form_args,
)
end

def captcha_validation_performed?
!recaptcha_form.exempt?
end

def process_failed_captcha
sign_out(:user)
warden.lock!
Expand Down Expand Up @@ -140,6 +152,11 @@ def check_user_needs_redirect
end
end

def user_from_params
return @user_from_params if defined?(@user_from_params)
@user_from_params = User.find_with_email(auth_params[:email])
end

def auth_params
params.require(:user).permit(:email, :password)
end
Expand Down Expand Up @@ -169,21 +186,23 @@ def handle_valid_authentication
user_id: current_user.id,
email: auth_params[:email],
)
user_session[:captcha_validation_performed_at_sign_in] = captcha_validation_performed?
user_session[:platform_authenticator_available] =
params[:platform_authenticator_available] == 'true'
check_password_compromised
redirect_to next_url_after_valid_authentication
end

def track_authentication_attempt(email)
user = User.find_with_email(email) || AnonymousUser.new
def track_authentication_attempt
user = user_from_params || AnonymousUser.new

success = current_user.present? && !user_locked_out?(user) && valid_captcha_result?
analytics.email_and_password_auth(
success: success,
user_id: user.uuid,
user_locked_out: user_locked_out?(user),
rate_limited: rate_limited?,
captcha_validation_performed: captcha_validation_performed?,
valid_captcha_result: valid_captcha_result?,
bad_password_count: session[:bad_password_count].to_i,
sp_request_url_present: sp_session[:request_url].present?,
Expand All @@ -202,7 +221,7 @@ def rate_limited?

def rate_limiter
return @rate_limiter if defined?(@rate_limiter)
user = User.find_with_email(auth_params[:email])
user = user_from_params
return @rate_limiter = nil unless user
@rate_limiter = RateLimiter.new(
rate_limit_type: :sign_in_user_id_per_ip,
Expand Down
25 changes: 19 additions & 6 deletions app/forms/sign_in_recaptcha_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,37 @@ class SignInRecaptchaForm

RECAPTCHA_ACTION = 'sign_in'

attr_reader :form_class, :form_args, :email, :recaptcha_token, :device_cookie
attr_reader :form_class, :form_args, :email, :recaptcha_token, :device_cookie, :ab_test_bucket

validate :validate_recaptcha_result

def initialize(form_class: RecaptchaForm, **form_args)
def initialize(
email:,
device_cookie:,
ab_test_bucket:,
form_class: RecaptchaForm,
**form_args
)
@email = email
@device_cookie = device_cookie
@ab_test_bucket = ab_test_bucket
@form_class = form_class
@form_args = form_args
end

def submit(email:, recaptcha_token:, device_cookie:)
@email = email
def submit(recaptcha_token:)
@recaptcha_token = recaptcha_token
@device_cookie = device_cookie

success = valid?
FormResponse.new(success:, errors:, serialize_error_details_only: true)
end

def exempt?
IdentityConfig.store.sign_in_recaptcha_score_threshold.zero? ||
ab_test_bucket != :sign_in_recaptcha ||
device.present?
end

private

def validate_recaptcha_result
Expand All @@ -35,7 +48,7 @@ def device
end

def score_threshold
if IdentityConfig.store.sign_in_recaptcha_score_threshold.zero? || device.present?
if exempt?
0.0
else
IdentityConfig.store.sign_in_recaptcha_score_threshold
Expand Down
5 changes: 4 additions & 1 deletion app/forms/webauthn_setup_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def generic_error_message

private

attr_reader :success, :transports, :invalid_transports, :protocol
attr_reader :success, :transports, :aaguid, :invalid_transports, :protocol
attr_accessor :user, :challenge, :attestation_object, :client_data_json,
:name, :platform_authenticator, :authenticator_data_flags, :device_name

Expand Down Expand Up @@ -110,6 +110,7 @@ def valid_attestation_response?(protocol)
)

begin
@aaguid = attestation_response.authenticator_data.aaguid
attestation_response.valid?(@challenge.pack('c*'), original_origin)
rescue StandardError
false
Expand Down Expand Up @@ -141,6 +142,7 @@ def create_webauthn_configuration
platform_authenticator: platform_authenticator,
transports: transports.presence,
authenticator_data_flags: authenticator_data_flags,
aaguid: aaguid,
)
end

Expand Down Expand Up @@ -172,6 +174,7 @@ def extra_analytics_attributes
pii_like_keypaths: [[:mfa_method_counts, :phone]],
authenticator_data_flags: authenticator_data_flags,
unknown_transports: invalid_transports.presence,
aaguid: aaguid,
}.compact
end
end
2 changes: 2 additions & 0 deletions app/forms/webauthn_verification_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def valid_assertion_response?
client_data_json.blank? ||
signature.blank? ||
challenge.blank?

WebAuthn::AuthenticatorAssertionResponse.new(
authenticator_data: Base64.decode64(authenticator_data),
client_data_json: Base64.decode64(client_data_json),
Expand Down Expand Up @@ -165,6 +166,7 @@ def extra_analytics_attributes
{
webauthn_configuration_id: webauthn_configuration&.id,
frontend_error: webauthn_error.presence,
webauthn_aaguid: webauthn_configuration&.aaguid,
}.compact
end
end
6 changes: 2 additions & 4 deletions app/jobs/reports/fraud_metrics_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def perform(date = Time.zone.yesterday.end_of_day)

ReportMailer.tables_report(
email: email_addresses,
subject: "Fraud Metrics Report - #{date.to_date}",
subject: "Fraud Metrics Report - #{report_date.to_date}",
reports: reports,
message: preamble,
attachment_format: :xlsx,
Expand Down Expand Up @@ -60,9 +60,7 @@ def preamble(env: Identity::Hostdata.env || 'local')
end

def reports
@reports ||= [
fraud_metrics_lg99_report.as_emailable_reports,
]
@reports ||= fraud_metrics_lg99_report.as_emailable_reports
end

def fraud_metrics_lg99_report
Expand Down
16 changes: 15 additions & 1 deletion app/jobs/resolution_proofing_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ def perform(
device_profiling_success: callback_log_data&.device_profiling_success,
timing: timer.results,
)

if IdentityConfig.store.idv_socure_shadow_mode_enabled
SocureShadowModeProofingJob.perform_later(
document_capture_session_result_id: document_capture_session.result_id,
encrypted_arguments:,
service_provider_issuer:,
user_email: user_email_for_proofing(user),
user_uuid: user.uuid,
)
end
end

private
Expand All @@ -89,7 +99,7 @@ def make_vendor_proofing_requests(
)
result = progressive_proofer.proof(
applicant_pii: applicant_pii,
user_email: user.confirmed_email_addresses.first.email,
user_email: user_email_for_proofing(user),
threatmetrix_session_id: threatmetrix_session_id,
request_ip: request_ip,
ipp_enrollment_in_progress: ipp_enrollment_in_progress,
Expand All @@ -109,6 +119,10 @@ def make_vendor_proofing_requests(
)
end

def user_email_for_proofing(user)
user.confirmed_email_addresses.first.email
end

def log_threatmetrix_info(threatmetrix_result, user)
logger_info_hash(
name: 'ThreatMetrix',
Expand Down
Loading

0 comments on commit d74df5a

Please sign in to comment.