fusionauth-issues
fusionauth-issues copied to clipboard
Can send a code during step up auth when user has only TOTP authenticator
Can send a code during step up auth when user has only TOTP authenticator
Description
During step up auth, as documented here and here, you can provide an optional code
parameter. This allows you to use step up auth with alternate delivery methods (slack, carrier pigeon).
However, when providing the code, if the user only has TOTP enabled, it doesn't make sense to allow the code
parameter to be sent. This is because the whole point of TOTP is the shared secret means there's no need for delivery of a code.
We should disallow any start requests that contain a code
when the user has TOTP enabled. Additionally, if the user has TOTP and a delivery based mechanism, the code
should not be used for the TOTP auth method, but instead the calculated value based on the time and the shared secret should be used.
Affects versions
1.36.4
Steps to reproduce
- Enable TOTP on an account. I did it with this curl script:
curl -XPATCH -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/user/00000000-0000-0000-0000-000000000004' -d '{"user": {"twoFactor": {"methods": [ {"authenticator": {"algorithm": "HmacSHA1", "codeLength": 6, "timeStep": 30}, "id": "Q4CZ", "method": "authenticator"} ] }}}'
- Start step up auth:
REQUEST_PAYLOAD='{ "loginId": "[email protected]", "applicationId": "3c219e58-ed0e-4b18-ad48-f4f92793ae32", "code": "123456" }' curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/start' -d "$REQUEST_PAYLOAD"
You'll get back this: {"code":"123456","methods":[{"authenticator":{"algorithm":"HmacSHA1","codeLength":6,"timeStep":30},"id":"QJGG","method":"authenticator"}],"twoFactorId":"mecpLEbalBVoziJPGeauIod-jaHRkQlZEEuxE304ZGY"}
If you actually try to complete the step up, you end up getting an error from FusionAuth and a NPE in the system logs, as mentioned here: https://github.com/FusionAuth/fusionauth-issues/issues/1715#issuecomment-1119796308
Expected behavior
Any 2fa happening where the code is provided and an authenticator app is used should ignore the code (for the authenticator method).
Community guidelines
All issues filed in this repository must abide by the FusionAuth community guidelines.
In this example, can you then use the code 123456
to complete the Two-Factor Login (/api/two-factor/login
)?
Yes.
I updated the doc here: https://github.com/FusionAuth/fusionauth-site/pull/1373 to make it more clear that you shouldn't provide the code, but if you do, the step up completes.
Actually, I'm wrong. I get this message when I complete the step up:
{"generalErrors":[{"code":"[Exception]","message":"FusionAuth encountered an unexpected error. Please review the troubleshooting guide found in the documentation for assistance and the available support channels."}]}
And in the system log I see:
teststepupauth-fusionauth-1 | java.lang.NullPointerException: Cannot invoke "String.getBytes(java.nio.charset.Charset)" because "src" is null
teststepupauth-fusionauth-1 | at java.base/java.util.Base64$Decoder.decode(Base64.java:589)
teststepupauth-fusionauth-1 | at io.fusionauth.api.service.authentication.DefaultAuthenticationService.validateTOTP(DefaultAuthenticationService.java:665)
teststepupauth-fusionauth-1 | at io.fusionauth.api.service.authentication.DefaultAuthenticationService.validateTwoFactorCode(DefaultAuthenticationService.java:409)
teststepupauth-fusionauth-1 | at io.fusionauth.api.service.authentication.DefaultAuthenticationService.authenticateTwoFactor(DefaultAuthenticationService.java:222)
teststepupauth-fusionauth-1 | at io.fusionauth.app.action.api.twoFactor.LoginAction.lambda$post$0(LoginAction.java:55)
teststepupauth-fusionauth-1 | at io.fusionauth.app.action.api.BaseLoginAction.callLogin(BaseLoginAction.java:175)
teststepupauth-fusionauth-1 | at io.fusionauth.app.action.api.twoFactor.LoginAction.post(LoginAction.java:55)
teststepupauth-fusionauth-1 | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)