Open anaps-qa opened 1 year ago
Similarly, an expired activation link is still accessible, allowing the user to go through the "false" activation process once again.
Additionally, a resending a new activation link does not invalidate the original activation link.
I'll use this issue to capture my notes on the subject. We are using the Djoser library to handle user auth, which includes the account activation, password reset, and email change workflows.
The Djoser email class generates the token and adds it to the email payload. https://github.com/sunscrapers/djoser/blob/bacf083b212bda1bf6eab2bf3f1c17e3dd5ba8ad/djoser/email.py#L17
This is using the Django built-in PasswordResetTokenGenerator
to create the token.
https://github.com/django/django/blob/ea8cbca579cc6742e119747fc1eb6ecf90638bce/django/contrib/auth/tokens.py#L40
Hash invalidation is explained here: https://github.com/django/django/blob/ea8cbca579cc6742e119747fc1eb6ecf90638bce/django/contrib/auth/tokens.py#L100
Hash the user's primary key, email (if available), and some user state
that's sure to change after a password reset to produce a token that is
invalidated when it's used:
1. The password field will change upon a password reset (even if the
same password is chosen, due to password salting).
2. The last_login field will usually be updated very shortly after
a password reset.
Failing those things, settings.PASSWORD_RESET_TIMEOUT eventually
invalidates the token.
Therefore token invalidation is limited to changes to email
, password
, or last_login
.
An improvement would be to also include a security_hash
on the user model which can be updated on any auth requests, such as how .NET IdentityFramework does it.
Furthermore, token validation occurs in the UidAndTokenSerializer
class here:
https://github.com/sunscrapers/djoser/blob/bacf083b212bda1bf6eab2bf3f1c17e3dd5ba8ad/djoser/serializers.py#L187
This is the base class for ActivationSerializer
, which is defined as the serializer for the activate
action here, if not overridden in settings:
https://github.com/sunscrapers/djoser/blob/bacf083b212bda1bf6eab2bf3f1c17e3dd5ba8ad/djoser/views.py#L100
Therefore the act of replacing a serializer on any auth endpoints could render token validation silently disabled, as could any conf
changes to serializers for related functions.
My takeaways so far are that token invalidation is not easily customizable, application security verification of our overridden Djoser functions is very difficult, and we should be very hesitant to any serializer changes without a comprehensive understanding of the underlying library code.
The Djoser source code uses manual updates to last_login
to invalidate old tokens:
https://github.com/sunscrapers/djoser/blob/bacf083b212bda1bf6eab2bf3f1c17e3dd5ba8ad/djoser/views.py#L252
Describe the bug
After having activated an account via an activation link sent to their email, the user Is able to go through the activation process again just by following the same link, including adding a new password, and receive a message of a successful activation. However, if the user tries to log back in with the new password, it fails. So while they did not activate the account again, it still creates a "false" activation process because of how far the user is able to follow the steps for activation.
Expected behavior
The user shouldn't be able to activate or even appear to activate an already existing account with its original activation link
To Reproduce
Steps to reproduce the behavior:
Screenshots/Videos
https://github.com/Shift3/boilerplate-client-react/assets/103682123/50df34c3-9ed4-42f7-b97a-e5fa765d388d
Devices/Browsers:
Notes