tarak / django-password-policies

Django unicode-aware password policies.
Other
59 stars 92 forks source link

Enforce password changes #7

Open matijakolaric opened 10 years ago

matijakolaric commented 10 years ago

I suggest a Setting that forces password changes on first login, as this is required by many safety standards.

tarak commented 10 years ago

You're right! But as I'm busy this might take a couple of days to work on. Did you already think about how to implement it? Suggestions are welcome...

matijakolaric commented 10 years ago

middleware.py, line 60

This is code that works for me: else: request.session[self.last] = request.user.date_joined - settings.PASSWORD_DURATION_SECONDS

This is a hack that would work, thought there must be a muct better way else: if (settings.PASSWORD_ENFORCE_CHANGE_ON_FIRST_LOGIN): request.session[self.last] = request.user.date_joined - settings.PASSWORD_DURATION_SECONDS else: request.session[self.last] = request.user.date_joined

tarak commented 10 years ago

I've actually thought about it. As I'm using customized User models a lot I don't want to rely on User model fields like user.date_joined. Who knows if it's available in other use cases than the Django standard user model.This is what I have in mind:

I've added a model with a 1-to-1 relationship to auth.User. I'm already extending the middleware.

I'm trying to not interfere with the User model to keep the password_policies app as "stand-alone" as possible.

Taking your suggestion a little bit further than you've intended I will also change the subject of this issue. Hope you don't mind...

matijakolaric commented 10 years ago

Great! Only one note ... after user forgets the password and admin resets it, on first login change must be enforced again.

tarak commented 10 years ago

That's why I added an admin action. In the admin interface you can decide if you just reset the password and/or trigger the admin action to enforce a password change after having reset the password. What I haven't thought about is if the user is supposed to change his/her password instantly or after he/she logs in again... That might be worth another setting, actually... What do you think?

If you want to have a checkbox on the admin passwort reset view you could use your own form to do so:

from password_policies.models import PasswordChangeRequired
from password_policies.forms import PasswordPoliciesForm

class PasswordPoliciesChangeRequiredForm(PasswordPoliciesForm):
    require_change = forms.BooleanField(label=_("require password change", default=True)

def save(self, commit=True):
    user = super(PasswordPoliciesChangeRequiredForm, self).save(commit=True)
    if 'require_change' in self.cleaned_data and self.cleaned_data['require_change']:
        PasswordChangeRequired.objects.create(user=user)
    return user

Then you could define your own password reset view for the admin interface. There you could test if the user who's resetting the password resets his/her own or another user's password. Based on that you could decide to use the form example written above or the normal password reset form. You wouldn't want to enforce a password change on yourself if you just changed your own password, would you?

matijakolaric commented 10 years ago

Well, the project that I am working on at the moment is health related and the rules are very strict. After the password is reset (automatically by lost password or by the administrator), at next login it must be changed. So neither the password in the mail or the one admin set can be misused.

tarak commented 10 years ago

Can you reread my comment? I've just updated it...

matijakolaric commented 10 years ago

Well, admin+grappelli has two views for changing password, one is from the status bar of the admin interface (admin/password_change/), so you change your own password, the other one is through user object (admin/auth/user/1/password/).

So, if admin changes his own password through the latter interface, yes, I would force him to change it again.

And in this particular instance of FDA and EMEA rules, strictly speaking, admin must not have this choice.

I know, distrusting admin seems strange, but those are the rules. We are used that admins in Django are also system administrators, but in big systems this is not the case. And often this would be against safety protocols.

I do not wish to be ungrateful, this is a great thing you do. But I have to go now and will be back on Tuesday.

tarak commented 10 years ago

OK. Well, to force a password change all you will have to do is to create an PasswordChangeRequired instance like:

PasswordChangeRequired.objects.create(user=user)

This could be done while creating a user or after having changed his/her password. The middleware would search for entries in the PasswordChangeRequired database table and, if one is found, redirect the user to the password change view.

tarak commented 10 years ago

I've just commited the changes so far. If you want to have a look... I would appreciate your opinion on what I've done... Maybe there's something I haven't thought about...