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
27 changes: 22 additions & 5 deletions app/controllers/users/verify_personal_key_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,32 @@ def new
user: current_user,
personal_key: '',
)

if Throttler::IsThrottled.call(current_user.id, :verify_personal_key)
render :throttled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to write something to the analytics hash when we're throttled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, something should be logged. #4803 created new events. Does it make sense to keep that pattern here too (and for an upcoming PR on rate limiting GPO attempts)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also: LG-4404

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Andrew's work in #4803 made it much easier, only had to pass in analytics to the throttle call and it took care of the rest. Also updated the specs.

else
render :new
end
end

def create
result = personal_key_form.submit
analytics.track_event(Analytics::PERSONAL_KEY_REACTIVATION_SUBMITTED, result.to_h)
if result.success?
handle_success(result)
throttled = Throttler::IsThrottledElseIncrement.call(
current_user.id,
:verify_personal_key,
analytics: analytics,
)

if throttled
render :throttled
else
handle_failure(result)
result = personal_key_form.submit

analytics.track_event(Analytics::PERSONAL_KEY_REACTIVATION_SUBMITTED, result.to_h)
if result.success?
handle_success(result)
else
handle_failure(result)
end
end
end

Expand Down
5 changes: 5 additions & 0 deletions app/models/throttle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Throttle < ApplicationRecord
reset_password_email: 4,
idv_resolution: 5,
idv_send_link: 6,
verify_personal_key: 7,
}

THROTTLE_CONFIG = {
Expand Down Expand Up @@ -36,6 +37,10 @@ class Throttle < ApplicationRecord
max_attempts: AppConfig.env.idv_send_link_max_attempts.to_i,
attempt_window: AppConfig.env.idv_send_link_attempt_window_in_minutes.to_i,
},
verify_personal_key: {
max_attempts: AppConfig.env.verify_personal_key_max_attempts.to_i,
attempt_window: AppConfig.env.verify_personal_key_attempt_window_in_minutes.to_i,
},
}.freeze

def throttled?
Expand Down
9 changes: 9 additions & 0 deletions app/views/users/verify_personal_key/throttled.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<% title t('headings.verify_personal_key') %>

<h1>
<%= t('headings.verify_personal_key') %>
</h1>

<p>
<%= t('errors.verify_personal_key.throttled') %> <%= link_to(t('links.go_back'), account_path) %>.
</p>
4 changes: 4 additions & 0 deletions config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ usps_download_sftp_timeout: '5'
usps_upload_enabled: 'false'
usps_upload_sftp_timeout: '5'
valid_authn_contexts: '["http://idmanagement.gov/ns/assurance/loa/1", "http://idmanagement.gov/ns/assurance/loa/3", "http://idmanagement.gov/ns/assurance/ial/1", "http://idmanagement.gov/ns/assurance/ial/2", "http://idmanagement.gov/ns/assurance/ial/0", "http://idmanagement.gov/ns/assurance/ial/2?strict=true", "urn:gov:gsa:ac:classes:sp:PasswordProtectedTransport:duo", "http://idmanagement.gov/ns/assurance/aal/2", "http://idmanagement.gov/ns/assurance/aal/3", "http://idmanagement.gov/ns/assurance/aal/3?hspd12=true"]'
verify_personal_key_attempt_window_in_minutes: '15'
verify_personal_key_max_attempts: '5'
usps_ipp_password: ''
usps_ipp_root_url: ''
usps_ipp_sponsor_id: ''
Expand Down Expand Up @@ -452,6 +454,8 @@ test:
session_encryption_key: 27bad3c25711099429c1afdfd1890910f3b59f5a4faec1c85e945cb8b02b02f261ba501d99cfbb4fab394e0102de6fecf8ffe260f322f610db3e96b2a775c120
sps_over_quota_limit_notify_email_list: '["test1@test.com"]'
telephony_adapter: test
verify_personal_key_attempt_window_in_minutes: '3'
verify_personal_key_max_attempts: '1'
use_dashboard_service_providers: 'false'
use_kms: 'false'
usps_confirmation_max_days: '10'
Expand Down
2 changes: 2 additions & 0 deletions config/locales/errors/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ en:
unique_name: That name is already taken. Please choose a different name.
two_factor_auth_setup:
must_select_option: Select an authentication method.
verify_personal_key:
throttled: You tried too many times, please try again in 15 minutes.
webauthn_setup:
already_registered: Security key already registered. Please try a different
security key.
Expand Down
2 changes: 2 additions & 0 deletions config/locales/errors/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ es:
unique_name: El nombre ya fue escogido. Por favor, elija un nombre diferente.
two_factor_auth_setup:
must_select_option: Seleccione un método de autenticación.
verify_personal_key:
throttled: Lo intentaste muchas veces, vuelve a intentarlo en 15 minutos.
webauthn_setup:
already_registered: Clave de seguridad ya registrada. Por favor, intente una
clave de seguridad diferente.
Expand Down
2 changes: 2 additions & 0 deletions config/locales/errors/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ fr:
unique_name: Ce nom est déjà pris. Veuillez choisir un autre nom.
two_factor_auth_setup:
must_select_option: Sélectionnez une méthode d'authentification.
verify_personal_key:
throttled: Vous avez essayé plusieurs fois, essayez à nouveau dans 15 minutes.
webauthn_setup:
already_registered: Clé de sécurité déjà enregistrée. Veuillez essayer une clé
de sécurité différente.
Expand Down
1 change: 1 addition & 0 deletions config/locales/headings/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@ en:
totp_setup:
new: Add an authentication app
verify_email: Check your email
verify_personal_key: Verify your personal key
webauthn_setup:
new: Add your security key
1 change: 1 addition & 0 deletions config/locales/headings/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@ es:
totp_setup:
new: Agregar una aplicación de autenticación
verify_email: Revise su email
verify_personal_key: Verifica tu clave personal
webauthn_setup:
new: Añade tu clave de seguridad
1 change: 1 addition & 0 deletions config/locales/headings/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ fr:
totp_setup:
new: Ajouter une application d'authentification
verify_email: Consultez vos courriels
verify_personal_key: Vérifier votre clé personnelle
webauthn_setup:
new: Ajoutez votre clé de sécurité
34 changes: 34 additions & 0 deletions spec/controllers/users/verify_personal_key_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@

expect(subject.flash[:info]).to eq(t('notices.account_reactivation'))
end

it 'shows throttled page after being throttled' do
allow(Throttler::IsThrottled).to receive(:call).once.and_return(true)
get :new

expect(response).to render_template(:throttled)
end
end
end

Expand Down Expand Up @@ -86,5 +93,32 @@
expect(response).to render_template(:new)
end
end

context 'with throttle reached' do
let(:bad_key) { 'baaad' }
before do
allow(VerifyPersonalKeyForm).to receive(:new).
with(user: subject.current_user, personal_key: bad_key).
and_return(form)
allow(form).to receive(:submit).and_return(response_bad)
end

it 'renders throttled page' do
stub_analytics
expect(@analytics).to receive(:track_event).with(
Analytics::PERSONAL_KEY_REACTIVATION_SUBMITTED,
{ errors: { personal_key: ['bad_key'] }, success: false },
).once
expect(@analytics).to receive(:track_event).with(
Analytics::THROTTLER_RATE_LIMIT_TRIGGERED,
throttle_type: 'verify_personal_key',
).once

post :create, params: { personal_key: bad_key }
post :create, params: { personal_key: bad_key }

expect(response).to render_template(:throttled)
end
end
end
end