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/forms/personal_key_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def submit
@success = valid?

reset_sensitive_fields unless success
send_personal_key_sign_in_notification if success

FormResponse.new(success: success, errors: errors.messages, extra: extra_analytics_attributes)
end
Expand All @@ -32,4 +33,13 @@ def extra_analytics_attributes
def reset_sensitive_fields
self.personal_key = nil
end

def send_personal_key_sign_in_notification
user.confirmed_email_addresses.each do |email_address|
UserMailer.personal_key_sign_in(email_address.email).deliver_now
end
MfaContext.new(user).phone_configurations.each do |phone_configuration|
SmsPersonalKeySignInNotifierJob.perform_now(phone: phone_configuration.phone)
end
end
end
14 changes: 14 additions & 0 deletions app/jobs/sms_personal_key_sign_in_notifier_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class SmsPersonalKeySignInNotifierJob < ApplicationJob
queue_as :sms

# :reek:UtilityFunction
def perform(phone:)
TwilioService::Utils.new.send_sms(
to: phone,
body: I18n.t(
'jobs.sms_personal_key_sign_in_notifier_job.message',
app: APP_NAME
)
)
end
end
4 changes: 4 additions & 0 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ def account_does_not_exist(email, request_id)
mail(to: email, subject: t('user_mailer.account_does_not_exist.subject'))
end

def personal_key_sign_in(email)
mail(to: email, subject: t('user_mailer.personal_key_sign_in.subject'))
end

def account_reset_request(email_address, account_reset)
@token = account_reset&.request_token
mail(to: email_address.email, subject: t('user_mailer.account_reset_request.subject'))
Expand Down
16 changes: 16 additions & 0 deletions app/views/user_mailer/personal_key_sign_in.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
p.lead
strong == t('.intro')

table.spacer
tbody
tr
td.s10 height="10px"
| &nbsp;
table.hr
tr
th
| &nbsp;

p == t('.help_html',
reset_password_url: forgot_password_url,
account_url: account_url)
3 changes: 3 additions & 0 deletions config/locales/jobs/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ en:
in to your account. This code will expire in %{expiration} minutes."
verify_message: "%{code} is your %{app} confirmation code. Use this to confirm
your phone number. This code will expire in %{expiration} minutes."
sms_personal_key_sign_in_notifier_job:
message: Your personal key was just used to sign into your login.gov account.
If this wasn’t you, reset your password and contact us at security@login.gov.
3 changes: 3 additions & 0 deletions config/locales/jobs/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ es:
ingresando a su cuenta. Este código caducará en %{expiration} minutos."
verify_message: "%{code} es tu código de confirmación de %{app}. Use esto para
confirmar su número de teléfono. Este código caducará en %{expiration} minutos."
sms_personal_key_sign_in_notifier_job:
message: Su clave personal solo se utilizó para iniciar sesión en su cuenta
login.gov. Si no fue así, reinicie su contraseña y contáctenos en security@login.gov.
4 changes: 4 additions & 0 deletions config/locales/jobs/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ fr:
verify_message: "%{code} est votre code de confirmation %{app}. Utilisez-le
pour confirmer votre numéro de téléphone. Ce code expirera dans %{expiration}
minutes."
sms_personal_key_sign_in_notifier_job:
message: Votre clé personnelle a été utilisée pour vous connecter à votre compte
login.gov. Si ce n’était pas vous, changez votre mot de passe et contactez-nous
à security@login.gov.
18 changes: 18 additions & 0 deletions config/locales/user_mailer/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ en:
help: If you did not make this change, please visit the %{app} %{help_link}
or %{contact_link}.
intro: You have a new password for your %{app} account.
personal_key_sign_in:
help_html: <p>Your login.gov account was just signed into using your 16-character
personal key. You're getting this email to make sure it was you.</p> <p>If
you just signed in using your personal key, great! There's nothing you need
to do.</p><p>If you did not sign in with a personal key, or if you're not
sure, please immediately take these steps to secure your account:<ol><li><strong><a
href="%{reset_password_url}">Change your password</a>.</strong> Choose a password
that you haven't already used with this account.</li><li><strong><a href="%{account_url}">Sign
in to your login.gov account</a></strong> and make sure you recognize all
of the information on your account page, including the methods you use for
two-factor authentication, such as phone number, authentication app, or security
key.</li><li><strong>On your login.gov account page, request a new personal
key.</strong> Remember, never share it unless you are using it to sign into
a trusted website that uses login.gov.</li></ol></p><p>You should then contact
us by calling 844-875-6446 or emailing <a href="mailto:security@login.gov">security@login.gov</a>.</p>
<br>Thanks,<br>The login.gov team
intro: Personal key used to sign in
subject: Account Security Alert
phone_changed:
help: If you did not want to change your phone number, please visit the %{app}
%{help_link} or %{contact_link}.
Expand Down
20 changes: 20 additions & 0 deletions config/locales/user_mailer/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ es:
password_changed:
help: Si no realizó este cambio, visite el %{app} %{help_link} o el %{contact_link}.
intro: Tiene una contraseña nueva para su cuenta de %{app}.
personal_key_sign_in:
help_html: <p>Su cuenta login.gov acaba de iniciar sesión con su clave personal
de 16 caracteres. Usted está recibiendo este e-mail para asegurarse de que
era usted.</p><p>Si acaba de iniciar sesión con su clave personal, ¡genial!
No hay nada que tenga que hacer.</p><p>Si no inició sesión con una clave personal,
o si no está seguro, por favor, siga estos pasos de inmediato para proteger
su cuenta.<ol><li><strong><a href="%{reset_password_url}">Cambie tu contraseña</a>.</strong>
Elija una contraseña que no haya utilizado con esta cuenta.</li><li><strong><a
href="%{account_url}">Inicie sesión en su cuenta login.gov</a></strong> y
asegúrese de reconocer toda la información en la página de su cuenta, incluidos
los métodos que utiliza para la autenticación de dos factores, como el número
de teléfono, la aplicación de autenticación, o la clave de seguridad.</li><li><strong>En
la página de su cuenta login.gov, solicite una nueva clave personal.</strong>
Recuerde, nunca lo comparta a menos que lo esté utilizando para iniciar sesión
en un sitio web de confianza que utiliza login.gov.</li></ol></p><p>Luego
debe comunicarse con nosotros llamando al 844-875-6446 o enviando un e-mail
a <a href="mailto:security@login.gov">security@login.gov</a>.</p> <br>Gracias,<br>El
equipo de login.gov
intro: Clave personal utilizada para iniciar sesión
subject: Alerta de seguridad de cuenta
phone_changed:
help: Si no desea cambiar su número de teléfono, visite el %{app} %{help_link}
o el %{contact_link}.
Expand Down
21 changes: 21 additions & 0 deletions config/locales/user_mailer/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ fr:
help: Si vous n'avez pas changé votre mot de passe, veuillez visiter le %{help_link}
de %{app} ou %{contact_link}.
intro: Le mot de passe de votre compte %{app} a été changé.
personal_key_sign_in:
help_html: <p>Votre compte login.gov a été connecté à l'aide de votre clé personnelle.
Vous recevez cet email pour vous assurer que c'était bien vous.</p><p>Si vous
venez de vous connecter avec votre clé personnelle, c'est parfait! Vous ne
devez rien faire.</p><p>Si vous ne vous êtes pas connecté avec une clé personnelle
ou si vous n’êtes pas sûr, prenez immédiatement les mesures suivantes pour
sécuriser votre compte:<ol><li><strong><a href="%{reset_password_url}">Changez
votre mot de passe</a>.</strong> Choisissez un mot de passe que vous n'avez
pas encore utilisé avec ce compte.</li><li><strong><a href="%{account_url}">Connectez-vous
à votre compte login.gov</a></strong> et assurez-vous de reconnaître toutes
les informations de la page de votre compte, y compris les méthodes que vous
utilisez pour l'authentification à deux facteurs, telles que le numéro de
téléphone, l'application d'authentification ou la clé de sécurité.</li><li><strong>Sur
la page de votre compte login.gov, demandez une nouvelle clé personnelle.</strong>
N'oubliez pas de ne jamais le partager à moins que vous ne l'utilisiez pour
vous connecter à un site Web de confiance utilisant login.gov.</li></ol></p><p>Vous
devriez a nous contacter par téléphone au 844-875-6446 ou par courriel à <a
href="mailto:security@login.gov">security@login.gov</a>.</p><br>Merci,<br>L'équipe
login.gov
intro: La clé personnelle utilisée pour vous connecter
subject: Alerte de sécurité du compte
phone_changed:
help: Si vous ne souhaitiez pas changer votre numéro de téléphone, veuillez
visiter le %{help_link} de %{app} ou %{contact_link}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
require 'rails_helper'

feature 'Signing in via one-time use personal key' do
it 'destroys old key, displays new one, and redirects to profile after acknowledging' do
user = create(:user, :signed_up)
it 'destroys old key, displays new one, notifies, and redirects to profile after acknowledging' do
user = create(:user, :signed_up, :with_phone, with: { phone: '+1 (202) 345-6789' })
raw_key = PersonalKeyGenerator.new(user).create
old_key = user.reload.encrypted_recovery_code_digest

personal_key_sign_in_mail = double
expect(personal_key_sign_in_mail).to receive(:deliver_now)
expect(UserMailer).to receive(:personal_key_sign_in).and_return(personal_key_sign_in_mail)
expect(SmsPersonalKeySignInNotifierJob).to receive(:perform_now).
with(phone: '+1 (202) 345-6789')

sign_in_before_2fa(user)
choose_another_security_option('personal_key')
enter_personal_key(personal_key: raw_key)
Expand Down
1 change: 1 addition & 0 deletions spec/features/users/sign_in_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@
# this can happen if you submit the personal key form multiple times quickly
it 'redirects to the personal key page' do
user = create(:user, :signed_up)
stub_twilio_service
old_personal_key = PersonalKeyGenerator.new(user).create
signin(user.email, user.password)
choose_another_security_option('personal_key')
Expand Down
20 changes: 20 additions & 0 deletions spec/forms/personal_key_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@
expect(form.submit).to eq result
expect(user.reload.encrypted_recovery_code_digest).to eq old_code
end

it 'sends an email and SMS notification to the user' do
user = create(
:user,
:with_phone,
email: 'jonny.hoops@gsa.gov',
with: { phone: '+1 (202) 345-6789' }
)
raw_code = PersonalKeyGenerator.new(user).create

personal_key_sign_in_mail = double
expect(personal_key_sign_in_mail).to receive(:deliver_now)
expect(UserMailer).to receive(:personal_key_sign_in).
with('jonny.hoops@gsa.gov').
and_return(personal_key_sign_in_mail)
expect(SmsPersonalKeySignInNotifierJob).to receive(:perform_now).
with(phone: '+1 (202) 345-6789')

PersonalKeyForm.new(user, raw_code).submit
end
end

context 'when the form is invalid' do
Expand Down
2 changes: 0 additions & 2 deletions spec/jobs/sms_account_reset_notifier_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
it 'sends a message containing the cancel link to the mobile number', twilio: true do
allow(Figaro.env).to receive(:twilio_messaging_service_sid).and_return('fake_sid')

TwilioService::Utils.telephony_service = FakeSms

perform

messages = FakeSms.messages
Expand Down
30 changes: 30 additions & 0 deletions spec/jobs/sms_personal_key_sign_in_notifier_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'rails_helper'

describe SmsPersonalKeySignInNotifierJob do
include Features::ActiveJobHelper

before do
reset_job_queues
TwilioService::Utils.telephony_service = FakeSms
FakeSms.messages = []
end

describe '.perform' do
it 'sends a message about the personal key sign in to the user' do
allow(Figaro.env).to receive(:twilio_messaging_service_sid).and_return('fake_sid')

described_class.perform_now(phone: '+1 (202) 345-6789')

messages = FakeSms.messages

expect(messages.size).to eq(1)

msg = messages.first

expect(msg.messaging_service_sid).to eq('fake_sid')
expect(msg.to).to eq('+1 (202) 345-6789')
expect(msg.body).
to eq(I18n.t('jobs.sms_personal_key_sign_in_notifier_job.message', app: APP_NAME))
end
end
end
20 changes: 20 additions & 0 deletions spec/mailers/user_mailer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@
end
end

describe 'personal_key_sign_in' do
let(:mail) { UserMailer.personal_key_sign_in(user.email) }

it_behaves_like 'a system email'

it 'sends to the current email' do
expect(mail.to).to eq [user.email]
end

it 'renders the subject' do
expect(mail.subject).to eq t('user_mailer.personal_key_sign_in.subject')
end

it 'renders the body' do
expect(mail.html_part.body).to have_content(
t('user_mailer.personal_key_sign_in.intro')
)
end
end

describe 'signup_with_your_email' do
let(:mail) { UserMailer.signup_with_your_email(user.email) }

Expand Down
1 change: 1 addition & 0 deletions spec/support/shared_examples/sign_in.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

shared_examples 'signing in as LOA3 with personal key' do |sp|
it 'redirects to the SP after acknowledging new personal key', :email do
stub_twilio_service
user = create_loa3_account_go_back_to_sp_and_sign_out(sp)
pii = { ssn: '666-66-1234', dob: '1920-01-01', first_name: 'alice' }

Expand Down