Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to implement a "change password at next logon" type feature in the django admin?

Tags:

I want to be able to set an option in the user's settings that forces them to change their password upon the next login to the admin interface. Is this possible? How would it go about being implemented? I'm using the default auth model right now but not opposed to modifying or changing it. Thanks for any help.

like image 267
bparker Avatar asked Jan 19 '10 13:01

bparker


People also ask

How do I change my Django admin password?

To change a user's password, you have several options:manage.py changepassword *username* offers a method of changing a user's password from the command line. It prompts you to change the password of a given user which you must enter twice. If they both match, the new password will be changed immediately.

What is the Django command to create a user or password for the admin user interface?

To create a new admin user in Django, we use the createsuperuser command, and this command can be executed using the manage.py utility. Once we execute the given command, it will prompt some fields like Username, Email, Password, Confirm Password.

Is there any password field in Django?

The Django's Forms The above form has two inputs - a text field named username (the name attribute in the html input field is what determines the name of input field) and a password field named password - and a submit button. The form uses POST method to submit form data to server.

How are passwords stored in Django?

Django provides a flexible password storage system and uses PBKDF2 by default. Those are the components used for storing a User's password, separated by the dollar-sign character and consist of: the hashing algorithm, the number of algorithm iterations (work factor), the random salt, and the resulting password hash.


1 Answers

I'm actually in the process of doing this myself. You need three components: a user profile (if not already in use on your site), a middleware component, and a pre_save signal.

My code for this is in an app named 'accounts'.

# myproject/accounts/models.py  from django.db import models from django.db.models import signals from django.contrib.auth.models import User  class UserProfile(models.Model):     user = models.ForeignKey(User, unique=True)     force_password_change = models.BooleanField(default=False)  def create_user_profile_signal(sender, instance, created, **kwargs):     if created:         UserProfile.objects.create(user=instance)  def password_change_signal(sender, instance, **kwargs):     try:         user = User.objects.get(username=instance.username)         if not user.password == instance.password:           profile = user.get_profile()           profile.force_password_change = False           profile.save()     except User.DoesNotExist:         pass  signals.pre_save.connect(password_change_signal, sender=User, dispatch_uid='accounts.models')  signals.post_save.connect(create_user_profile_signal, sender=User, dispatch_uid='accounts.models') 

First, we create a UserProfile with a foreign key to User. The force_password_change boolean will, as its name describes, be set to true for a user whenever you want to force them to change their password. You could do anything here though. In my organization, we also chose to implement a mandatory change every 90 days, so I also have a DateTimeField that stores the last time a user changed their password. You then set that in the pre_save signal, password_changed_signal.

Second, we have the create_user_profile_signal. This is mostly added just for completeness. If you're just now adding user profiles into your project, you'll need a post_save signal that will create a UserProfile every time a User is created. This accomplishes that task.

Third, we have the password_changed_signal. This is a pre_save signal because at this point in the process the actual row in the User table hasn't be updated. Therefore, we can access both the previous password and the new password about to be saved. If the two don't match, that means the user has changed their password, and we can then reset the force_password_change boolean. This would be the point, also where you would take care of any other things you've added such as setting the DateTimeField previously mentioned.

The last two lines attach the two functions to their appropriate signals.

If you haven't already, you will also need to add the following line to your project's settings.py (changing the app label and model name to match your setup):

AUTH_PROFILE_MODULE = 'accounts.UserProfile' 

That covers the basics. Now we need a middleware component to check the status of our force_password_change flag (and any other necessary checks).

# myproject/accounts/middleware.py  from django.http import HttpResponseRedirect  import re  class PasswordChangeMiddleware:     def process_request(self, request):         if request.user.is_authenticated() and \             re.match(r'^/admin/?', request.path) and \             not re.match(r'^/admin/password_change/?', request.path):              profile = request.user.get_profile()             if profile.force_password_change:                 return HttpResponseRedirect('/admin/password_change/') 

This very simple middleware hooks into the process_request stage of the page loading process. It checks that 1) the user has already logged in, 2) they are trying to access some page in the admin, and 3) the page they are accessing is not the password change page itself (otherwise, you'd get an infinite loop of redirects). If all of these are true and the force_password_change flag has been set to True, then the user is redirected to the password change page. They will not be able to navigate anywhere else until they change their password (firing the pre_save signal discussed previously).

Finally, you just need to add this middleware to your project's settings.py (again, changing the import path as necessary):

MIDDLEWARE_CLASSES = (     # Other middleware here     'myproject.accounts.middleware.PasswordChangeMiddleware', ) 
like image 65
Chris Pratt Avatar answered Sep 22 '22 01:09

Chris Pratt