#28285: Updating Password Hasher Invalidates Users First Login After Upgrade
---------------------------------+--------------------------------------
     Reporter:  Simon Blanchard  |                    Owner:  nobody
         Type:  Bug              |                   Status:  new
    Component:  contrib.auth     |                  Version:  1.11
     Severity:  Normal           |               Resolution:
     Keywords:                   |             Triage Stage:  Unreviewed
    Has patch:  0                |      Needs documentation:  0
  Needs tests:  0                |  Patch needs improvement:  0
Easy pickings:  0                |                    UI/UX:  0
---------------------------------+--------------------------------------

Old description:

> The code below, from contrib.auth.base_user.py, says "hash upgrade is not
> a password change"
>
> {{{
>     def check_password(self, raw_password):
>         """
>         Return a boolean of whether the raw_password was correct. Handles
>         hashing formats behind the scenes.
>         """
>         def setter(raw_password):
>             self.set_password(raw_password)
>             # Password hash upgrades shouldn't be considered password
> changes.
>             self._password = None
>             self.save(update_fields=["password"])
>         return check_password(raw_password, self.password, setter)
> }}}
>

> but the code in contrib.auth.__init__.py/get_user()
>
> verifies the session by comparing a salted hmac of the password hash to
> the same thing stored in the session.
>
> If we update the password hash the salted hmac will change. Therefore,
> the session will no longer be considered valid and will be flushed. We
> can keep the session alive by updating the HASH_SESSION_KEY in
> request.session e.g. via the update_session_auth_hash() function. But
> this is not called by the setter function when the hasher is updated.
>
> So the first time the user logs (with the correct password) following an
> upgrade, their (valid) session will be flushed and they will be logged
> out again.

New description:

 The code below, from `contrib.auth.base_user.py`, says "hash upgrade is
 not a password change"

 {{{
     def check_password(self, raw_password):
         """
         Return a boolean of whether the raw_password was correct. Handles
         hashing formats behind the scenes.
         """
         def setter(raw_password):
             self.set_password(raw_password)
             # Password hash upgrades shouldn't be considered password
 changes.
             self._password = None
             self.save(update_fields=["password"])
         return check_password(raw_password, self.password, setter)
 }}}


 but the code in `contrib.auth.get_user()` verifies the session by
 comparing a salted hmac of the password hash to the same thing stored in
 the session.

 If we update the password hash the salted hmac will change. Therefore, the
 session will no longer be considered valid and will be flushed. We can
 keep the session alive by updating the `HASH_SESSION_KEY` in
 `request.session` e.g. via the `update_session_auth_hash()` function. But
 this is not called by the setter function when the hasher is updated.

 So the first time the user logs (with the correct password) following an
 upgrade, their (valid) session will be flushed and they will be logged out
 again.

--

Comment (by Tim Graham):

 Here's my understanding of the scenario:
 1. User X logs in and creates session A
 2. Number of hash iterations changes in Django due to a software upgrade
 3. Session A is still valid at this point
 4. For whatever reason (using a different browser perhaps), user X logs in
 and creates session B, triggering a password hash upgrade and an
 invalidation of session A

 I don't think there's a way to keep session A valid is this scenario. Am I
 misunderstanding something?

--
Ticket URL: <https://code.djangoproject.com/ticket/28285#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.7ce0d0632f9f4b0dac558307ace286ad%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to