Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ccc2b18
Jmax/lg 12260 use authn context resolver to compute legacy sp session…
jmax-gsa Feb 12, 2024
6cadf98
LG-12355: store reference in doc auth response extras for failed LN …
amirbey Feb 12, 2024
eb992e2
Jmax/LG-12134 Spike use absolute timestamps for rate limiter Redis ti…
jmax-gsa Feb 12, 2024
61b9fc1
LG-12017 fraud pending deadline passed (#10053)
svalexander Feb 12, 2024
f622ba2
Convert file-base64-cache.js to typescript (#10070)
Feb 12, 2024
44e502d
LG-12370: success_status to check if pii exists (#10077)
amirbey Feb 13, 2024
436969d
LG-12332: fix mock client to pass when using real image. (#10066)
dawei-nava Feb 13, 2024
1374c0f
Set allow_failure: true for production_deploy (#10079)
zachmargolis Feb 13, 2024
2502de3
Update OIG report format (#10054)
zachmargolis Feb 13, 2024
6f889cc
LG-11648 MFA method report (#10076)
Sgtpluck Feb 13, 2024
b54b3c8
changelog: Bug Fixes, Logo, missing gsa logo on login page (#10080)
nprimak Feb 13, 2024
bad499a
Update base layout to be base-ier (#10067)
aduth Feb 14, 2024
59dfbc6
Remove unused `@ial` ivar from `Users::SessionsController` (#10083)
jmhooper Feb 14, 2024
981c31d
LG-11600 Prevent circumnavigation of opt in step (#9987)
jack-ryan-nava-pbc Feb 14, 2024
8d3b70d
Remove unused code in MFA Report (#10081)
zachmargolis Feb 14, 2024
0f8b27c
LG-12080: Send `selfie_status` to FE (#10073)
charleyf Feb 14, 2024
6ea1c96
LG-12445: Attention to Barcode does not override a failed portrait ma…
amirbey Feb 15, 2024
4600159
Please Call Screen for IPP Threatmetrix review (#10033)
jack-ryan-nava-pbc Feb 15, 2024
aaa4ad5
Use Warden lock mechanism for session lockout (#10089)
aduth Feb 15, 2024
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 .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ stop-review-app:

deploy_production:
stage: deploy_production
allow_failure: false
allow_failure: true
needs:
- job: build-review-image
resource_group: $CI_ENVIRONMENT_SLUG.review-app.identitysandbox.gov
Expand Down
Binary file added app/assets/images/sp-logos/gsa.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ def render_timeout(exception)
end

def render_full_width(template, **opts)
render template, **opts, layout: 'base'
render template, **opts, layout: 'application'
end

def analytics_exception_info(exception)
Expand Down
18 changes: 18 additions & 0 deletions app/controllers/concerns/fraud_review_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,39 @@ module FraudReviewConcern
delegate :fraud_check_failed?,
:fraud_review_pending?,
:fraud_rejection?,
:ipp_fraud_review_pending?,
to: :fraud_review_checker

def handle_fraud
in_person_handle_pending_fraud_review
handle_pending_fraud_review
handle_fraud_rejection
end

def handle_pending_fraud_review
# If the user has not passed IPP at a post office, allow them to
# complete another enrollment by not redirecting to please call
return if in_person_can_perform_fraud_review?
redirect_to_fraud_review if fraud_review_pending?
end

def handle_fraud_rejection
redirect_to_fraud_rejection if fraud_rejection?
end

def in_person_handle_pending_fraud_review
return unless in_person_can_perform_fraud_review?
if fraud_review_pending? && current_user.in_person_enrollment_status == 'passed'
redirect_to_fraud_review
end
end

def in_person_can_perform_fraud_review?
IdentityConfig.store.in_person_proofing_enforce_tmx &&
current_user.in_person_enrollment_status != 'canceled' &&
!current_user.in_person_enrollment_status.nil?
end

def redirect_to_fraud_review
redirect_to idv_please_call_url
end
Expand Down
5 changes: 4 additions & 1 deletion app/controllers/idv/how_to_verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def self.step_info
idv_session.idv_consent_given &&
idv_session.service_provider&.in_person_proofing_enabled
end,
undo_step: ->(idv_session:, user:) { idv_session.skip_doc_auth = nil },
undo_step: ->(idv_session:, user:) {
idv_session.skip_doc_auth = nil
idv_session.opted_in_to_in_person_proofing = nil
},
)
end

Expand Down
15 changes: 14 additions & 1 deletion app/controllers/idv/hybrid_handoff_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,25 @@ def update
end
end

def self.selected_remote(idv_session:)
if IdentityConfig.store.in_person_proofing_opt_in_enabled &&
IdentityConfig.store.in_person_proofing_enabled &&
idv_session.service_provider&.in_person_proofing_enabled
idv_session.skip_doc_auth == false
else
idv_session.skip_doc_auth.nil? || idv_session.skip_doc_auth == false
end
end

def self.step_info
Idv::StepInfo.new(
key: :hybrid_handoff,
controller: self,
next_steps: [:link_sent, :document_capture],
preconditions: ->(idv_session:, user:) { idv_session.idv_consent_given },
preconditions: ->(idv_session:, user:) {
idv_session.idv_consent_given &&
self.selected_remote(idv_session: idv_session)
},
undo_step: ->(idv_session:, user:) do
idv_session.flow_path = nil
idv_session.phone_for_mobile_flow = nil
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/idv/in_person/ready_to_verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ class ReadyToVerifyController < ApplicationController
include RenderConditionConcern
include StepIndicatorConcern
include OptInHelper
include FraudReviewConcern

check_or_render_not_found -> { IdentityConfig.store.in_person_proofing_enabled }

before_action :handle_fraud
before_action :confirm_two_factor_authenticated
before_action :confirm_in_person_session

Expand Down
19 changes: 19 additions & 0 deletions app/controllers/idv/please_call_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ def show
analytics.idv_please_call_visited
pending_at = current_user.fraud_review_pending_profile.fraud_review_pending_at
@call_by_date = pending_at + FRAUD_REVIEW_CONTACT_WITHIN_DAYS
@in_person = ipp_enabled_and_enrollment_passed?
end

def ipp_enabled_and_enrollment_passed?
return unless in_person_tmx_enabled?
in_person_proofing_enabled? && ipp_enrollment_passed?
end

private
Expand All @@ -22,5 +28,18 @@ def confirm_fraud_pending
redirect_to account_url
end
end

def in_person_proofing_enabled?
IdentityConfig.store.in_person_proofing_enabled
end

def in_person_tmx_enabled?
IdentityConfig.store.in_person_proofing_enforce_tmx
end

# we only want to handle enrollments that have passed
def ipp_enrollment_passed?
current_user&.in_person_enrollment_status == 'passed'
end
end
end
8 changes: 3 additions & 5 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class SessionsController < Devise::SessionsController
def new
override_csp_for_google_analytics

@ial = sp_session_ial
@issuer_forced_reauthentication = issuer_forced_reauthentication?(
issuer: decorated_sp_session.sp_issuer,
)
Expand Down Expand Up @@ -76,10 +75,9 @@ def increment_session_bad_password_count
end

def process_locked_out_session
irs_attempts_api_tracker.login_rate_limited(
email: auth_params[:email],
)

irs_attempts_api_tracker.login_rate_limited(email: auth_params[:email])
warden.logout(:user)
warden.lock!
flash[:error] = t('errors.sign_in.bad_password_limit')
redirect_to root_url
end
Expand Down
8 changes: 6 additions & 2 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ def title
end
end

def background_cls(cls)
content_for(:background_cls) { cls }
def extends_layout(layout, **locals, &block)
if block.present?
@view_flow.get(:layout).replace capture(&block) # rubocop:disable Rails/HelperInstanceVariable
end

render template: "layouts/#{layout}", locals:
end

def sp_session
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createContext } from 'react';

const FileBase64CacheContext = createContext(/** @type {WeakMap<Blob,string>} */ (new WeakMap()));
const FileBase64CacheContext = createContext(new WeakMap<Blob, string>());

FileBase64CacheContext.displayName = 'FileBase64CacheContext';

Expand Down
7 changes: 7 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,13 @@ def in_person_pending_profile
pending_profile if pending_profile&.in_person_verification_pending?
end

##
# Return the status of the current In Person Proofing Enrollment
# @return [String] enrollment status
def in_person_enrollment_status
pending_profile&.in_person_enrollment&.status
end

def has_in_person_enrollment?
pending_in_person_enrollment.present? || establishing_in_person_enrollment.present?
end
Expand Down
11 changes: 8 additions & 3 deletions app/presenters/image_upload_response_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def as_json(*)
json[:ocr_pii] = ocr_pii
json[:result_failed] = doc_auth_result_failed?
json[:doc_type_supported] = doc_type_supported?
json[:selfie_live] = selfie_live? if show_selfie_failures
json[:selfie_quality_good] = selfie_quality_good? if show_selfie_failures
json[:selfie_status] = selfie_status if show_selfie_failures?
json[:selfie_live] = selfie_live? if show_selfie_failures?
json[:selfie_quality_good] = selfie_quality_good? if show_selfie_failures?
json[:failed_image_fingerprints] = failed_fingerprints
json
end
Expand Down Expand Up @@ -90,10 +91,14 @@ def failed_fingerprints
@form_response.extra[:failed_image_fingerprints] || { front: [], back: [], selfie: [] }
end

def show_selfie_failures
def show_selfie_failures?
@form_response.extra[:liveness_checking_required] == true
end

def selfie_status
@form_response.respond_to?(:selfie_status) ? @form_response.selfie_status : :not_processed
end

def selfie_live?
@form_response.respond_to?(:selfie_live?) ? @form_response.selfie_live? : true
end
Expand Down
4 changes: 3 additions & 1 deletion app/services/doc_auth/lexis_nexis/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def handle_connection_error(exception:, status_code: nil, status_message: nil)
selfie_quality_good: false,
vendor_status_code: status_code,
vendor_status_message: status_message,
reference: @reference,
}.compact,
)
end
Expand Down Expand Up @@ -146,13 +147,14 @@ def hmac_authorization
end

def settings
@reference = uuid
{
Type: 'Initiate',
Settings: {
Mode: request_mode,
Locale: config.locale,
Venue: 'online',
Reference: uuid,
Reference: @reference,
},
}
end
Expand Down
12 changes: 2 additions & 10 deletions app/services/doc_auth/lexis_nexis/responses/true_id_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def initialize(http_response, config, liveness_checking_enabled = false)
# document type
# bar code attention
def successful_result?
(all_passed? || attention_with_barcode?) && id_type_supported?
doc_auth_success? &&
(@liveness_checking_enabled ? selfie_passed? : true)
end

# all checks from document perspectives, without considering selfie:
Expand Down Expand Up @@ -193,15 +194,6 @@ def basic_logging_info
}
end

# Status of all checks from Vendor perspective
def all_passed?
transaction_status_passed? &&
true_id_product.present? &&
product_status_passed? &&
doc_auth_result_passed? &&
(@liveness_checking_enabled ? selfie_passed? : true)
end

def selfie_result
portrait_match_results&.dig(:FaceMatchResult)
end
Expand Down
8 changes: 6 additions & 2 deletions app/services/doc_auth/mock/doc_auth_mock_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,13 @@ def post_images(
back_image_response = post_back_image(image: back_image, instance_id: instance_id)
return back_image_response unless back_image_response.success?

get_results(instance_id: instance_id)
get_results(
instance_id: instance_id,
selfie_required: liveness_checking_required,
)
end

def get_results(instance_id:)
def get_results(instance_id:, selfie_required: false)
return mocked_response_for_method(__method__) if method_mocked?(__method__)
error_response = http_error_response(self.class.last_uploaded_back_image, 'result')
return error_response if error_response
Expand All @@ -91,6 +94,7 @@ def get_results(instance_id:)
ResultResponse.new(
self.class.last_uploaded_back_image,
overriden_config,
selfie_required,
)
end
# rubocop:enable Lint/UnusedMethodArgument
Expand Down
13 changes: 10 additions & 3 deletions app/services/doc_auth/mock/result_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ class ResultResponse < DocAuth::Response

attr_reader :uploaded_file, :config

def initialize(uploaded_file, config)
def initialize(uploaded_file, config, selfie_required = false)
@uploaded_file = uploaded_file.to_s
@config = config
@selfie_required = selfie_required
super(
success: success?,
errors: errors,
Expand All @@ -22,6 +23,7 @@ def initialize(uploaded_file, config)
portrait_match_results: portrait_match_results,
billed: true,
classification_info: classification_info,
liveness_checking_required: @selfie_required,
}.compact,
)
end
Expand Down Expand Up @@ -138,8 +140,12 @@ def doc_auth_success?
end

def selfie_status
return :not_processed if portrait_match_results&.dig(:FaceMatchResult).nil?
portrait_match_results[:FaceMatchResult] == 'Pass' ? :success : :fail
if @selfie_required
return :success if portrait_match_results&.dig(:FaceMatchResult).nil?
portrait_match_results[:FaceMatchResult] == 'Pass' ? :success : :fail
else
:not_processed
end
end

private
Expand Down Expand Up @@ -240,6 +246,7 @@ def create_response_info(
liveness_enabled: liveness_enabled,
classification_info: classification_info,
portrait_match_results: selfie_check_performed? ? portrait_match_results : nil,
extra: { liveness_checking_required: liveness_enabled },
}.compact
end
end
Expand Down
3 changes: 3 additions & 0 deletions app/services/doc_auth/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def initialize(
pii_from_doc: {},
attention_with_barcode: false,
doc_type_supported: true,
selfie_status: :not_processed,
selfie_live: true,
selfie_quality_good: true
)
Expand All @@ -28,6 +29,7 @@ def initialize(
@pii_from_doc = pii_from_doc
@attention_with_barcode = attention_with_barcode
@doc_type_supported = doc_type_supported
@selfie_status = selfie_status
@selfie_live = selfie_live
@selfie_quality_good = selfie_quality_good
end
Expand All @@ -41,6 +43,7 @@ def merge(other)
pii_from_doc: pii_from_doc.merge(other.pii_from_doc),
attention_with_barcode: attention_with_barcode? || other.attention_with_barcode?,
doc_type_supported: doc_type_supported? || other.doc_type_supported?,
selfie_status: selfie_status,
selfie_live: selfie_live?,
selfie_quality_good: selfie_quality_good?,
)
Expand Down
2 changes: 1 addition & 1 deletion app/services/document_capture_session_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def selfie_status

def success_status
# doc_auth_success : including document, attention_with_barcode and id type verification
!!doc_auth_success && selfie_status != :fail
!!doc_auth_success && selfie_status != :fail && !!pii
end

alias_method :success?, :success_status
Expand Down
Loading