diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index ff1476b15b1..9885e2afa96 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -256,9 +256,6 @@ def after_sign_in_path_for(_user)
return login_add_piv_cac_prompt_url if session[:needs_to_setup_piv_cac_after_sign_in].present?
return reactivate_account_url if user_needs_to_reactivate_account?
return login_piv_cac_recommended_path if user_recommended_for_piv_cac?
- return webauthn_platform_recommended_path if recommend_webauthn_platform_for_sms_user?(
- :recommend_for_authentication,
- )
return second_mfa_reminder_url if user_needs_second_mfa_reminder?
return backup_code_reminder_url if user_needs_backup_code_reminder?
return sp_session_request_url_with_updated_params if sp_session.key?(:request_url)
diff --git a/app/controllers/concerns/mfa_setup_concern.rb b/app/controllers/concerns/mfa_setup_concern.rb
index b08c215e8ce..138a22a5364 100644
--- a/app/controllers/concerns/mfa_setup_concern.rb
+++ b/app/controllers/concerns/mfa_setup_concern.rb
@@ -2,12 +2,11 @@
module MfaSetupConcern
extend ActiveSupport::Concern
- include RecommendWebauthnPlatformConcern
def next_setup_path
if next_setup_choice
confirmation_path
- elsif recommend_webauthn_platform_for_sms_user?(:recommend_for_account_creation)
+ elsif recommend_webauthn_platform_for_sms_user?
webauthn_platform_recommended_path
elsif suggest_second_mfa?
auth_method_confirmation_path
@@ -129,4 +128,21 @@ def next_setup_choice
determine_next_mfa,
)
end
+
+ def recommend_webauthn_platform_for_sms_user?
+ user_session[:platform_authenticator_available] == true && user_has_phone_setup?
+ end
+
+ def user_set_up_with_sms?
+ current_user.phone_configurations.any? do |phone_configuration|
+ phone_configuration.mfa_enabled? && phone_configuration.delivery_preference == 'sms'
+ end
+ end
+
+ def user_has_phone_setup?
+ user_session[:in_account_creation_flow] == true &&
+ mfa_context.enabled_mfa_methods_count == 1 &&
+ mfa_context.phone_configurations.present? &&
+ user_set_up_with_sms?
+ end
end
diff --git a/app/controllers/concerns/recommend_webauthn_platform_concern.rb b/app/controllers/concerns/recommend_webauthn_platform_concern.rb
deleted file mode 100644
index 2cb9a5fb6d1..00000000000
--- a/app/controllers/concerns/recommend_webauthn_platform_concern.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module RecommendWebauthnPlatformConcern
- def recommend_webauthn_platform_for_sms_user?(bucket)
- # Only consider for A/B test if:
- # 1. Option would be offered for setup
- # 2. User is viewing content in English
- # 3. Other recommendations have not already been offered (e.g. PIV/CAC for federal emails)
- # 4. User selected to setup phone or authenticated with phone
- # 5. User has not already set up a platform authenticator
- return false if !device_supports_platform_authenticator_setup?
- return false if I18n.locale != :en
- return false if current_user.webauthn_platform_recommended_dismissed_at?
- return false if !user_set_up_or_authenticated_with_phone?
- return false if current_user.webauthn_configurations.platform_authenticators.present?
- ab_test_bucket(:RECOMMEND_WEBAUTHN_PLATFORM_FOR_SMS_USER) == bucket
- end
-
- private
-
- def device_supports_platform_authenticator_setup?
- user_session[:platform_authenticator_available] == true
- end
-
- def in_account_creation_flow?
- user_session[:in_account_creation_flow] == true
- end
-
- def user_set_up_or_authenticated_with_phone?
- if in_account_creation_flow?
- current_user.phone_configurations.any? do |phone_configuration|
- phone_configuration.mfa_enabled? && phone_configuration.delivery_preference == 'sms'
- end
- else
- auth_methods_session.auth_events
- .pluck(:auth_method)
- .include?(TwoFactorAuthenticatable::AuthMethod::SMS)
- end
- end
-end
diff --git a/app/controllers/users/webauthn_platform_recommended_controller.rb b/app/controllers/users/webauthn_platform_recommended_controller.rb
index aa18b9b6eeb..ceb500504f5 100644
--- a/app/controllers/users/webauthn_platform_recommended_controller.rb
+++ b/app/controllers/users/webauthn_platform_recommended_controller.rb
@@ -3,7 +3,6 @@
module Users
class WebauthnPlatformRecommendedController < ApplicationController
include SecureHeadersConcern
- include MfaSetupConcern
before_action :confirm_two_factor_authenticated
before_action :apply_secure_headers_override
@@ -15,22 +14,13 @@ def new
def create
analytics.webauthn_platform_recommended_submitted(opted_to_add: opted_to_add?)
- store_webauthn_platform_recommended_in_session if opted_to_add?
+ user_session[:webauthn_platform_recommended] = true if opted_to_add?
current_user.update(webauthn_platform_recommended_dismissed_at: Time.zone.now)
redirect_to dismiss_redirect_path
end
private
- def store_webauthn_platform_recommended_in_session
- user_session[:webauthn_platform_recommended] =
- if in_account_creation_flow?
- :account_creation
- else
- :authentication
- end
- end
-
def opted_to_add?
params[:add_method].present?
end
@@ -38,10 +28,8 @@ def opted_to_add?
def dismiss_redirect_path
if opted_to_add?
webauthn_setup_path(platform: true)
- elsif in_account_creation_flow?
- next_setup_path || after_mfa_setup_path
else
- after_sign_in_path_for(current_user)
+ after_mfa_setup_path
end
end
end
diff --git a/app/views/users/webauthn_platform_recommended/new.html.erb b/app/views/users/webauthn_platform_recommended/new.html.erb
index 98b5d1cd925..c54a6800430 100644
--- a/app/views/users/webauthn_platform_recommended/new.html.erb
+++ b/app/views/users/webauthn_platform_recommended/new.html.erb
@@ -3,7 +3,8 @@
<%= render StatusPageComponent.new(status: :info, icon: :question) do |c| %>
<% c.with_header { t('webauthn_platform_recommended.heading') } %>
-
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 3ad55a76a35..11dd4528127 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -2046,9 +2046,10 @@ vendor_outage.get_updates: Get updates
vendor_outage.get_updates_on_status_page: Get updates on our status page
vendor_outage.working: We are working to resolve an error
webauthn_platform_recommended.cta: Set up face or touch unlock
-webauthn_platform_recommended.description_save_time: Save time by using your face, fingerprint, password, or another method to access your account. This method is faster than receiving a one-time code through text or voice message.
-webauthn_platform_recommended.heading: Set up face or touch unlock for a quick and easy sign in
+webauthn_platform_recommended.description_security: Secure your sign in with face or touch unlock. Use your face, fingerprint, password, or another method to keep your account safer.
+webauthn_platform_recommended.heading: Set up face or touch unlock for a more secure sign in
webauthn_platform_recommended.skip: Skip
+webauthn_platform_recommended.upsell: Face or touch unlock is phishing-resistant and we don’t store any recordings of your face or fingerprint, so your information stays private.
webauthn_setup_mismatch.description_undo: Click “Undo” to remove this option.
webauthn_setup_mismatch.description.webauthn: We noticed you’re using a security key instead of face or touch unlock. Click “Continue” to use your security key to sign in from now on.
webauthn_setup_mismatch.description.webauthn_platform: We noticed you’re using face or touch unlock instead of a security key. Click “Continue” to use face or touch unlock to sign in from now on.
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 7d407f80268..788d498b35e 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -2057,10 +2057,11 @@ vendor_outage.blocked.phone.default: No podemos verificar teléfonos en estos mo
vendor_outage.get_updates: Obtenga actualizaciones
vendor_outage.get_updates_on_status_page: Obtenga las actualizaciones en nuestra página de estado
vendor_outage.working: Estamos trabajando para corregir un error
-webauthn_platform_recommended.cta: Set up face or touch unlock
-webauthn_platform_recommended.description_save_time: Save time by using your face, fingerprint, password, or another method to access your account. This method is faster than receiving a one-time code through text or voice message.
-webauthn_platform_recommended.heading: Set up face or touch unlock for a quick and easy sign in
-webauthn_platform_recommended.skip: Skip
+webauthn_platform_recommended.cta: Configurar el desbloqueo facial o táctil
+webauthn_platform_recommended.description_security: Proteja su inicio de sesión con el desbloqueo facial o táctil. Use su rostro, huella dactilar, contraseña u otro método para mantener su cuenta más segura.
+webauthn_platform_recommended.heading: Configuración del desbloqueo facial o táctil para un inicio de sesión más seguro
+webauthn_platform_recommended.skip: Omitir
+webauthn_platform_recommended.upsell: El desbloqueo facial o táctil está protegido contra el phishing y no almacenamos ninguna grabación de su rostro ni de su huella dactilar, con el fin de resguardar la privacidad de su información.
webauthn_setup_mismatch.description_undo: Haga clic en “Deshacer” para quitar esta opción.
webauthn_setup_mismatch.description.webauthn: Sabemos que está usando una clave de seguridad en lugar de desbloqueo facial o táctil. Haga clic en “Continuar” para iniciar sesión con su clave de seguridad de aquí en adelante.
webauthn_setup_mismatch.description.webauthn_platform: Sabemos que está usando desbloqueo facial o táctil en lugar de una clave de seguridad. Haga clic en “Continuar” para iniciar sesión con desbloqueo facial o táctil de aquí en adelante.
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 4d3d7ea24a6..cac8ae158f5 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -2045,10 +2045,11 @@ vendor_outage.blocked.phone.default: Nous ne sommes pas actuellement en mesure d
vendor_outage.get_updates: Obtenir les dernières informations
vendor_outage.get_updates_on_status_page: Obtenir les dernières informations sur notre page d’état des systèmes.
vendor_outage.working: Nous travaillons à la résolution d’une erreur
-webauthn_platform_recommended.cta: Set up face or touch unlock
-webauthn_platform_recommended.description_save_time: Save time by using your face, fingerprint, password, or another method to access your account. This method is faster than receiving a one-time code through text or voice message.
-webauthn_platform_recommended.heading: Set up face or touch unlock for a quick and easy sign in
-webauthn_platform_recommended.skip: Skip
+webauthn_platform_recommended.cta: Configurer le déverrouillage facial ou tactile
+webauthn_platform_recommended.description_security: Save time by using your face, fingerprint, password, or another method to access your account. This method is faster than receiving a one-time code through text or voice message.
+webauthn_platform_recommended.heading: Configurar el desbloqueo facial o táctil
+webauthn_platform_recommended.skip: Ignorer
+webauthn_platform_recommended.upsell: La confidentialité de vos informations est assurée car le déverrouillage par reconnaissance faciale ou tactile résiste à l’hameçonnage et nous ne conservons aucun enregistrement de votre visage ou de vos empreintes digitales.
webauthn_setup_mismatch.description_undo: Cliquez sur « Annuler » pour supprimer cette option.
webauthn_setup_mismatch.description.webauthn: Nous avons remarqué que vous utilisiez une clé de sécurité au lieu du déverrouillage facial ou tactile. Cliquez sur « Suite » pour utiliser votre clé de sécurité afin de vous connecter à partir de maintenant.
webauthn_setup_mismatch.description.webauthn_platform: Nous avons remarqué que vous utilisiez le déverrouillage facial ou tactile au lieu d’une clé de sécurité. Cliquez sur « Suite » pour utiliser le déverrouillage facial ou tactile afin de vous connecter à partir de maintenant.
diff --git a/config/locales/zh.yml b/config/locales/zh.yml
index 93adc12d980..f294ddf7973 100644
--- a/config/locales/zh.yml
+++ b/config/locales/zh.yml
@@ -2058,10 +2058,11 @@ vendor_outage.blocked.phone.default: 我们目前无法验证电话。请稍后
vendor_outage.get_updates: 获得最新信息
vendor_outage.get_updates_on_status_page: 在我们的状态页面获得最新信息。
vendor_outage.working: 我们正在争取解决错误。
-webauthn_platform_recommended.cta: Set up face or touch unlock
-webauthn_platform_recommended.description_save_time: Save time by using your face, fingerprint, password, or another method to access your account. This method is faster than receiving a one-time code through text or voice message.
-webauthn_platform_recommended.heading: Set up face or touch unlock for a quick and easy sign in
-webauthn_platform_recommended.skip: Skip
+webauthn_platform_recommended.cta: 设置人脸或触摸解锁
+webauthn_platform_recommended.description_security: 使用人脸或触摸解锁来保护你的登录。使用你的面孔、指纹、密码或其他方法来使你的帐户更安全。
+webauthn_platform_recommended.heading: 设置人脸或触摸解锁以更安全地登录
+webauthn_platform_recommended.skip: 跳过
+webauthn_platform_recommended.upsell: 人脸或触摸解锁具有防网络钓鱼功能,而且我们不会存储任何人脸或指纹记录,使得你的信息能保持私密。
webauthn_setup_mismatch.description_undo: 点击“撤消”可删除此选项。
webauthn_setup_mismatch.description.webauthn: 我们注意到您正在使用安全密钥而不是人脸或触摸解锁。点击“继续”即可从现在开始使用您的安全密钥登录。
webauthn_setup_mismatch.description.webauthn_platform: 我们注意到您正在使用人脸或触摸解锁,而不是安全密钥。点击“继续”即可从现在开始使用人脸或触摸解锁登录。
diff --git a/spec/controllers/concerns/mfa_setup_concern_spec.rb b/spec/controllers/concerns/mfa_setup_concern_spec.rb
index 046184606b4..9369bdc1668 100644
--- a/spec/controllers/concerns/mfa_setup_concern_spec.rb
+++ b/spec/controllers/concerns/mfa_setup_concern_spec.rb
@@ -6,13 +6,9 @@
end
let(:user) { create(:user, :fully_registered) }
- let(:recommend_webauthn_platform_for_sms_user) { false }
before do
stub_sign_in(user)
- allow(controller).to receive(:recommend_webauthn_platform_for_sms_user?)
- .with(:recommend_for_account_creation)
- .and_return(recommend_webauthn_platform_for_sms_user)
end
describe '#next_setup_path' do
@@ -33,14 +29,6 @@
controller.user_session[:mfa_selections] = ['phone']
end
- context 'when user is recommended for webauthn platform for sms user' do
- let(:recommend_webauthn_platform_for_sms_user) { true }
-
- it 'returns webauthn platform recommended path' do
- expect(next_setup_path).to eq(webauthn_platform_recommended_path)
- end
- end
-
context 'when user only set up a single mfa method' do
it 'returns second mfa recommended path' do
expect(next_setup_path).to eq(auth_method_confirmation_path)
@@ -70,6 +58,21 @@
end
end
+ context 'when user is recommended for webauthn platform setup' do
+ before do
+ controller.user_session[:mfa_selections] = ['phone']
+ controller.user_session[:platform_authenticator_available] = true
+ controller.user_session[:in_account_creation_flow] = true
+ end
+
+ let(:user) { create(:user, :fully_registered) }
+ let(:recommend_webauthn_platform_for_sms_user?) { true }
+
+ it 'redirects to webauthn recommendation screen' do
+ expect(next_setup_path).to eq(webauthn_platform_recommended_path)
+ end
+ end
+
context 'when user converts from second mfa reminder' do
let(:user) { create(:user, :fully_registered, :with_phone, :with_backup_code) }
diff --git a/spec/controllers/concerns/recommend_webauthn_platform_concern_spec.rb b/spec/controllers/concerns/recommend_webauthn_platform_concern_spec.rb
deleted file mode 100644
index 7b240292679..00000000000
--- a/spec/controllers/concerns/recommend_webauthn_platform_concern_spec.rb
+++ /dev/null
@@ -1,181 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe RecommendWebauthnPlatformConcern do
- controller ApplicationController do
- include RecommendWebauthnPlatformConcern
- end
-
- let(:user) { create(:user, :fully_registered) }
- let(:platform_authenticator_available) { false }
- let(:in_account_creation_flow) { false }
-
- before do
- stub_sign_in(user)
- controller.user_session[:platform_authenticator_available] = platform_authenticator_available
- controller.user_session[:in_account_creation_flow] = in_account_creation_flow
- end
-
- describe '#recommend_webauthn_platform_for_sms_user?' do
- let(:bucket) { :recommend_for_account_creation }
-
- subject(:recommend_webauthn_platform_for_sms_user?) do
- controller.recommend_webauthn_platform_for_sms_user?(bucket)
- end
-
- context 'device is not supported for platform authenticator setup' do
- let(:platform_authenticator_available) { false }
-
- it { is_expected.to eq(false) }
- end
-
- context 'device is supported for platform authenticator setup' do
- let(:platform_authenticator_available) { true }
-
- context 'locale is anything other than english' do
- before do
- I18n.locale = (I18n.available_locales - [:en]).sample
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'locale is english' do
- before do
- I18n.locale = :en
- end
-
- context 'user was already recommended for setup' do
- let(:user) do
- create(
- :user,
- :fully_registered,
- webauthn_platform_recommended_dismissed_at: 2.minutes.ago,
- )
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user has not yet been recommended for setup' do
- let(:user) { create(:user, :fully_registered) }
-
- context 'user is in authentication flow' do
- let(:in_account_creation_flow) { false }
-
- context 'user authenticated with an mfa method other than sms' do
- before do
- controller.auth_methods_session.auth_events.clear
- controller.auth_methods_session.authenticate!(
- TwoFactorAuthenticatable::AuthMethod::VOICE,
- )
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user authenticated with sms' do
- before do
- controller.auth_methods_session.auth_events.clear
- controller.auth_methods_session.authenticate!(
- TwoFactorAuthenticatable::AuthMethod::SMS,
- )
- end
-
- context 'user has platform authenticator associated with their account' do
- let(:user) { create(:user, :fully_registered, :with_webauthn_platform) }
-
- it { is_expected.to eq(false) }
- end
-
- context 'user does not have platform authenticator associated with their account' do
- let(:user) { create(:user, :fully_registered) }
-
- context 'user not included in ab test' do
- before do
- expect(controller).to receive(:ab_test_bucket)
- .with(:RECOMMEND_WEBAUTHN_PLATFORM_FOR_SMS_USER)
- .and_return(nil)
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user included in ab test' do
- before do
- expect(controller).to receive(:ab_test_bucket)
- .with(:RECOMMEND_WEBAUTHN_PLATFORM_FOR_SMS_USER)
- .and_return(bucket)
- end
-
- it { is_expected.to eq(true) }
- end
- end
- end
- end
-
- context 'user is in account creation flow' do
- let(:in_account_creation_flow) { true }
-
- context 'user set up methods not including phone' do
- let(:user) { create(:user, :fully_registered, :with_authentication_app) }
-
- before do
- user.phone_configurations.destroy_all
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user set up phone as an mfa method' do
- let(:user) { create(:user, :fully_registered) }
-
- context 'user set up phone using voice delivery preference' do
- before do
- user.phone_configurations.update_all(delivery_preference: :voice)
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user set up phone using sms delivery preference' do
- before do
- user.phone_configurations.update_all(delivery_preference: :sms)
- end
-
- context 'user also set up platform authenticator' do
- let(:user) { create(:user, :fully_registered, :with_webauthn_platform) }
-
- it { is_expected.to eq(false) }
- end
-
- context 'user did not set up platform authenticator' do
- let(:user) { create(:user, :fully_registered) }
-
- context 'user not included in ab test' do
- before do
- expect(controller).to receive(:ab_test_bucket)
- .with(:RECOMMEND_WEBAUTHN_PLATFORM_FOR_SMS_USER)
- .and_return(nil)
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'user included in ab test' do
- before do
- expect(controller).to receive(:ab_test_bucket)
- .with(:RECOMMEND_WEBAUTHN_PLATFORM_FOR_SMS_USER)
- .and_return(bucket)
- end
-
- it { is_expected.to eq(true) }
- end
- end
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/spec/controllers/users/webauthn_platform_recommended_controller_spec.rb b/spec/controllers/users/webauthn_platform_recommended_controller_spec.rb
index 34937d03ba1..0ba3fa6ac9e 100644
--- a/spec/controllers/users/webauthn_platform_recommended_controller_spec.rb
+++ b/spec/controllers/users/webauthn_platform_recommended_controller_spec.rb
@@ -69,12 +69,6 @@
.from(nil)
end
- it 'redirects user to after sign in path' do
- expect(controller).to receive(:after_sign_in_path_for).with(user).and_return(account_path)
-
- expect(response).to redirect_to(account_path)
- end
-
context 'user is creating account' do
before do
allow(controller).to receive(:in_account_creation_flow?).and_return(true)
@@ -117,19 +111,14 @@
expect(response).to redirect_to(webauthn_setup_path(platform: true))
end
- it 'assigns recommended session value to recommendation flow' do
- expect { response }.to change { controller.user_session[:webauthn_platform_recommended] }
- .from(nil).to(:authentication)
- end
-
context 'user is creating account' do
before do
allow(controller).to receive(:in_account_creation_flow?).and_return(true)
end
- it 'assigns recommended session value to recommendation flow' do
+ it 'adds recommended session value during recommendation flow' do
expect { response }.to change { controller.user_session[:webauthn_platform_recommended] }
- .from(nil).to(:account_creation)
+ .from(nil).to(true)
end
end
end
diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb
index ae57f2198a5..de0d6b227c7 100644
--- a/spec/i18n_spec.rb
+++ b/spec/i18n_spec.rb
@@ -84,10 +84,6 @@ class BaseTask
{ key: 'time.formats.event_timestamp', locales: %i[zh] },
{ key: 'time.formats.full_date', locales: %i[es] }, # format is the same in Spanish and English
{ key: 'time.formats.sms_date' }, # for us date format
- { key: 'webauthn_platform_recommended.cta' }, # English-only A/B test
- { key: 'webauthn_platform_recommended.description_save_time' }, # English-only A/B test
- { key: 'webauthn_platform_recommended.heading' }, # English-only A/B test
- { key: 'webauthn_platform_recommended.skip' }, # English-only A/B test
].freeze
# rubocop:enable Layout/LineLength