The "Change Password" form in the admin site does not work when using a subclass of User
|Reported by:||ElliottM||Owned by:||nobody|
|Severity:||Keywords:||subclass user password change admin|
|Has patch:||no||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
Instead of using a profile model, I've decided to simplify things by using a subclass of auth's User model. It works seamlessly in all places. One of the few places it doesn't work is the admin site. When I click on the "change password" link in the password field's help text on the change page, "password/" is added to the url, but the same view is returned. If you keep clicking, it keeps adding more "password/"s onto the end of the URL, but the"change password" page never gets loaded.
The problem is in the django/contrib/admin/sites.py file. On line 21 the following regex is defined:
USER_CHANGE_PASSWORD_URL_RE = re.compile('auth/user/(\d+)/password')
Later on in the file, in AdminSite.root(), the following appears:
173 match = USER_CHANGE_PASSWORD_URL_RE.match(url) 174 if match: 175 return self.user_change_password(request, match.group(1))
An alternate User model will never match that regex, and thus the user_change_password view will never be called.
Furthermore, once that function does get called, it calls user_change_password in django.contrib.auth.views and this view again hard-codes a reference to User in it's call to get_object_or_404. If the PKs of User and the subclass do not match up, it may try to get a user that does not exist and raise a 404, or much worse, get a completely different user and change their password instead of the intended user.
The function has a TODO that says it should be moved to the UserAdmin. If the move was made, the reference to "User" could be changed to "self.model", which would mean the correct model will always be passed to get_object_or_404.