app/controllers/two_factor_authentication/piv_cac_verification_controller.rb
# frozen_string_literal: true
module TwoFactorAuthentication
class PivCacVerificationController < ApplicationController
include TwoFactorAuthenticatable
include PivCacConcern
include NewDeviceConcern
before_action :confirm_piv_cac_enabled, only: :show
before_action :reset_attempt_count_if_user_no_longer_locked_out, only: :show
def show
analytics.multi_factor_auth_enter_piv_cac(**analytics_properties)
if params[:token]
process_token
else
@presenter = presenter_for_two_factor_authentication_method
end
end
def redirect_to_piv_cac_service
create_piv_cac_nonce
redirect_to PivCacService.piv_cac_service_link(
nonce: piv_cac_nonce,
redirect_uri: login_two_factor_piv_cac_url,
), allow_other_host: true
end
private
def process_token
result = piv_cac_verification_form.submit
analytics.multi_factor_auth(**result.to_h.merge(analytics_properties))
session[:sign_in_flow] = :sign_in
if result.success?
handle_valid_piv_cac
else
handle_invalid_piv_cac
end
end
def handle_valid_piv_cac
clear_piv_cac_nonce
save_piv_cac_information(
subject: piv_cac_verification_form.x509_dn,
issuer: piv_cac_verification_form.x509_issuer,
presented: true,
)
handle_valid_verification_for_authentication_context(
auth_method: TwoFactorAuthenticatable::AuthMethod::PIV_CAC,
)
redirect_to after_sign_in_path_for(current_user)
end
def handle_invalid_piv_cac
clear_piv_cac_information
handle_invalid_otp(context: context, type: 'piv_cac')
end
# This overrides the method in TwoFactorAuthenticatable so that we
# redirect back to ourselves rather than rendering the :show template.
# This removes the token from the address bar and preserves the error
# in the flash.
def render_show_after_invalid
flash[:error] = flash.now[:error]
redirect_to login_two_factor_piv_cac_url
end
def piv_cac_view_data
{ two_factor_authentication_method: 'piv_cac' }.merge(generic_data)
end
def piv_cac_verification_form
@piv_cac_verification_form ||= UserPivCacVerificationForm.new(
user: current_user,
token: params[:token],
nonce: piv_cac_nonce,
piv_cac_required: service_provider_mfa_policy.piv_cac_required?,
)
end
def confirm_piv_cac_enabled
return if TwoFactorAuthentication::PivCacPolicy.new(current_user).enabled?
redirect_to user_two_factor_authentication_url
end
def presenter_for_two_factor_authentication_method
TwoFactorAuthCode::PivCacAuthenticationPresenter.new(
view: view_context,
data: piv_cac_view_data,
service_provider: current_sp,
remember_device_default: remember_device_default,
)
end
def analytics_properties
{
context: context,
multi_factor_auth_method: 'piv_cac',
piv_cac_configuration_id: piv_cac_verification_form&.piv_cac_configuration&.id,
new_device: new_device?,
}
end
end
end