LG-14261 Add attempt count to mfa setup auth events#11293
LG-14261 Add attempt count to mfa setup auth events#11293kevinsmaster5 merged 55 commits intomainfrom
Conversation
|
Taking a look at second_factor_attempts_count to see if that might take the place of creating a session token. |
seems to only work for OTP. |
mdiarra3
left a comment
There was a problem hiding this comment.
Looks good and seems to work locally, but wondering if theres a way for us to push this out to a helper or concern for the verification controllers.
Do you mean something like abstracting this sort of thing into a concern?
It does look repetitive since it's sort of identical in 4 places. |
|
Added suggestion from #11293 (review) |
aduth
left a comment
There was a problem hiding this comment.
The ticket wants this to be included for both setup and verification attempts, but the pull request is currently focused on setup only.
app/controllers/two_factor_authentication/otp_verification_controller.rb
Outdated
Show resolved
Hide resolved
|
If someone fails authenticating or setting up with one authentication method and then switches to another, what do we expect the I think we should either only log the attempts for that individual method, or the log value should be a hash of attempts for each method. For both cases, I'd imagine the session value would be a hash of method-to-attempts. |
So rather than Would we want to see something like |
|
I think we could keep the logged value a single integer if we wanted, but in order to make sure that we're only logging attempts for that method, we'd need to track the attempts in the session as per-method (a hash). So the session value would look something like the hash in your example, and getting the value from the session is something like |
aduth
left a comment
There was a problem hiding this comment.
I'm wondering if it'd be better to implement the incrementing
app/controllers/two_factor_authentication/options_controller.rb
Outdated
Show resolved
Hide resolved
app/controllers/two_factor_authentication/otp_verification_controller.rb
Outdated
Show resolved
Hide resolved
app/controllers/two_factor_authentication/otp_verification_controller.rb
Outdated
Show resolved
Hide resolved
spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb
Outdated
Show resolved
Hide resolved
app/controllers/two_factor_authentication/otp_verification_controller.rb
Outdated
Show resolved
Hide resolved
|
can you rebase this branch to pick up changes to the reviewapp deploy process? |
df8b957 to
da9afdf
Compare
There was a problem hiding this comment.
Do we log errors.personal_key and error_details.personal_key here? I'm surprised this would come up just now.
There was a problem hiding this comment.
It was in response to an error I was getting. I can take another look for more clarity.
There was a problem hiding this comment.
It was in the same spec that was exhibiting the session sensitive key error
./spec/features/legacy_passwords_spec.rb:61
-
legacy passwords signing in with an incorrect uak personal key digest does not grant access
Failure/Error:
raise PiiDetected, <<~ERROR
track_event received pii key path: #{current_keypath.inspect}
event: #{event} (#{constant_name})
full event: #{attributes.inspect}
allowlisted keypaths: #{pii_like_keypaths.inspect}
ERRORFakeAnalytics::PiiDetected:
track_event received pii key path: [:errors, :personal_key]
event: Multi-Factor Authentication ()
full event: {:success=>false, :errors=>{:personal_key=>["Incorrect personal key"]}, :error_details=>{:personal_key=>{:personal_key_incorrect=>true}}, :new_device=>true, :mfa_attempts=>{"personal_key"=>1}, :multi_factor_auth_method=>"personal-key", :enabled_mfa_methods_count=>1}
allowlisted keypaths: [[:mfa_attempts, :otp], [:error_details, :personal_key]]
There was a problem hiding this comment.
I'm not able to reproduce that test failure locally in your branch when removing this pii_like_keypaths code. Also, mfa_attempts.otp would never exist in the hash structure since you changed that in an earlier commit.
There was a problem hiding this comment.
I think now that we're only tracking attempts for the current method, and because auth_method is a redundant property, it'd be nice if we logged the numeric value of attempts instead.
| mfa_attempts: { | |
| attempts: 1, | |
| auth_method: 'sms', | |
| }, | |
| attempts: 1, |
There was a problem hiding this comment.
Revised expected analytics event with e6ab87d
There was a problem hiding this comment.
I'm not able to reproduce that test failure locally in your branch when removing this pii_like_keypaths code. Also, mfa_attempts.otp would never exist in the hash structure since you changed that in an earlier commit.
There was a problem hiding this comment.
I don't think this is accurately counting attempts. If I sat on the WebAuthn setup page and refreshed the page, it would count that as an attempt, but that's not really an attempt. I think we'd want this inside the result.errors.present? check above.
There was a problem hiding this comment.
I moved it there. I don't honestly know why that works. Do we expect errors to be present every time?
spec/lib/session_encryptor_spec.rb
Outdated
There was a problem hiding this comment.
I don't think we need these changes anymore?
There was a problem hiding this comment.
That's right. Those are removed.
…, improve method count helper
8f17b01 to
cb69a2c
Compare
| user_session[:mfa_attempts] ||= {} | ||
| user_session[:mfa_attempts][:attempts] ||= 0 | ||
| if user_session[:mfa_attempts][:auth_method] != auth_method | ||
| if user_session[:mfa_attempts][:auth_method].to_s != auth_method.to_s |
There was a problem hiding this comment.
webauthn gets converted to a string when it's added to the session
[2] pry(#Users::WebauthnSetupController)> auth_method
=> :webauthn.1 |
[3] pry(#Users::WebauthnSetupController)> user_session[:mfa_attempts]
it would always set the increment to zero because the 2 values were coming out inequal
There was a problem hiding this comment.
Thinking it's because the auth method may or may not be set to "_platform" 🤔
There was a problem hiding this comment.
Yes, that's a good call-out. The WebAuthn controller handles both Security Key and Face or Touch Unlock, and we probably want to differentiate with webauthn_platform vs. webauthn.
There was a problem hiding this comment.
This reminds me that we have constants defined for each of the expected auth_method values. Using these might also help with issues normalizing to string, since session value should always be a string.
identity-idp/app/controllers/concerns/two_factor_authenticatable.rb
Lines 18 to 26 in f7fcb4c
|
|
||
| def create | ||
| if UserSessionContext.confirmation_context?(context) | ||
| increment_mfa_selection_attempt_count(:otp) |
There was a problem hiding this comment.
@aduth should this (and others relative to their constants) be
| increment_mfa_selection_attempt_count(:otp) | |
| increment_mfa_selection_attempt_count(TwoFactorAuthenticatable::AuthMethod::PIV_CAC) |
for example regarding #11293 (comment)
There was a problem hiding this comment.
Yeah like that, as appropriate for each method.
There was a problem hiding this comment.
Got that in there. It also made the change here #11293 (comment) no longer needed.
There was a problem hiding this comment.
I still see the symbol :otp used here. Would we want to switch between TwoFactorAuthenticatable::AuthMethod::SMS or TwoFactorAuthenticatable::AuthMethod::VOICE like we're doing with WebAuthn, to be able to better differentiate what delivery method they're failing with?
| end | ||
|
|
||
| def confirm | ||
| increment_mfa_selection_attempt_count(:webauthn) |
There was a problem hiding this comment.
We'll want to use the constant here as well, and incorporate 'webauthn_platform'.
Maybe we want a helper method to avoid noisy if else ?
def webauthn_auth_method
if @platform_authenticator
TwoFactorAuthenticatable::AuthMethod::WEBAUTHN_PLATFORM
else
TwoFactorAuthenticatable::AuthMethod::WEBAUTHN
end
endThere was a problem hiding this comment.
That works great - also for sms/voice.
aduth
left a comment
There was a problem hiding this comment.
One minor suggestion, but LGTM otherwise 👍
| if @platform_authenticator | ||
| increment_mfa_selection_attempt_count( | ||
| TwoFactorAuthenticatable::AuthMethod::WEBAUTHN_PLATFORM, | ||
| ) | ||
| else | ||
| increment_mfa_selection_attempt_count( | ||
| TwoFactorAuthenticatable::AuthMethod::WEBAUTHN, | ||
| ) | ||
| end |
There was a problem hiding this comment.
We can use your new helper method to simplify
| if @platform_authenticator | |
| increment_mfa_selection_attempt_count( | |
| TwoFactorAuthenticatable::AuthMethod::WEBAUTHN_PLATFORM, | |
| ) | |
| else | |
| increment_mfa_selection_attempt_count( | |
| TwoFactorAuthenticatable::AuthMethod::WEBAUTHN, | |
| ) | |
| end | |
| increment_mfa_selection_attempt_count(webauthn_auth_method) |
There was a problem hiding this comment.
oh right! thanks :)
🎫 Ticket
Link to the relevant ticket:
LG-14261
🛠 Summary of changes
Adds a session token to track number of attempts when setting up an mfa type.
Total sum of attempts gets passed to analytics_events.
Backup codes are excluded since during setup they're added instantly.
📜 Testing Plan
Checklist of steps to confirm the changes.
properties > event_properties > mfa_attempts is registered
Attempt count will increment by failing and retrying to add mfa for example:
👀 Screenshots