-
Notifications
You must be signed in to change notification settings - Fork 354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finish password expiration #224
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
d4d0939
Expand tests, fix logic, add docs
grahamu 23edd12
Add mgmt commands and tests
grahamu c9c73d8
Add ExpiredPasswordMiddleware
grahamu d20a523
Fix documentation formatting
grahamu c2b3316
Update installation docs for pw expiration
grahamu ac43310
Improve verbiage
grahamu 527b9cc
Improve comments
grahamu f69f798
Add messages and signals
grahamu 06c4309
Send signal for password expired
grahamu 2954278
Improve admin display, expired pw message
grahamu 127613f
Add "?next=" when expired password detected
grahamu 3108ddb
Update test to check "?next=" in URL
grahamu 40d419d
Add ACCOUNT_LOGOUT_URL
grahamu 83c9efc
Add note about "staff" user skipping pw check
grahamu b557fd7
Update version: "2.0.0.dev2"
grahamu 1f44952
Add management command documentation
grahamu 55ae160
Fix docs
grahamu 1e0d672
Improve directions
grahamu d16099b
Improve commands doc
grahamu 32b7623
Use django.contrib.auth.REDIRECT_FIELD_NAME
grahamu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "2.0.0.dev1" | ||
__version__ = "2.0.0.dev2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from django.contrib.auth import get_user_model | ||
from django.core.management.base import LabelCommand | ||
|
||
from account.conf import settings | ||
from account.models import PasswordExpiry | ||
|
||
|
||
class Command(LabelCommand): | ||
|
||
help = "Create user-specific password expiration period." | ||
label = "username" | ||
|
||
def add_arguments(self, parser): | ||
super(Command, self).add_arguments(parser) | ||
parser.add_argument( | ||
"-e", "--expire", | ||
type=int, | ||
nargs="?", | ||
default=settings.ACCOUNT_PASSWORD_EXPIRY, | ||
help="number of seconds until password expires" | ||
) | ||
|
||
def handle_label(self, username, **options): | ||
User = get_user_model() | ||
try: | ||
user = User.objects.get(username=username) | ||
except User.DoesNotExist: | ||
return "User \"{}\" not found".format(username) | ||
|
||
expire = options["expire"] | ||
|
||
# Modify existing PasswordExpiry or create new if needed. | ||
if not hasattr(user, "password_expiry"): | ||
PasswordExpiry.objects.create(user=user, expiry=expire) | ||
else: | ||
user.password_expiry.expiry = expire | ||
user.password_expiry.save() | ||
|
||
return "User \"{}\" password expiration set to {} seconds".format(username, expire) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import datetime | ||
import pytz | ||
|
||
from django.contrib.auth import get_user_model | ||
from django.core.management.base import BaseCommand | ||
|
||
from account.models import PasswordHistory | ||
|
||
|
||
class Command(BaseCommand): | ||
|
||
help = "Create password history for all users without existing history." | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"-d", "--days", | ||
type=int, | ||
nargs="?", | ||
default=10, | ||
help="age of current password (in days)" | ||
) | ||
parser.add_argument( | ||
"-f", "--force", | ||
action="store_true", | ||
help="create new password history for all users, regardless of existing history" | ||
) | ||
|
||
def handle(self, *args, **options): | ||
User = get_user_model() | ||
users = User.objects.all() | ||
if not options["force"]: | ||
users = users.filter(password_history=None) | ||
|
||
if not users: | ||
return "No users found without password history" | ||
|
||
days = options["days"] | ||
timestamp = datetime.datetime.now(tz=pytz.UTC) - datetime.timedelta(days=days) | ||
|
||
# Create new PasswordHistory on `timestamp` | ||
PasswordHistory.objects.bulk_create( | ||
[PasswordHistory(user=user, timestamp=timestamp) for user in users] | ||
) | ||
|
||
return "Password history set to {} for {} users".format(timestamp, len(users)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
# -*- coding: utf-8 -*- | ||
# Generated by Django 1.9.7 on 2016-09-01 17:50 | ||
# Generated by Django 1.10.1 on 2016-09-13 08:55 | ||
from __future__ import unicode_literals | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import django.utils.timezone | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
@@ -28,7 +29,7 @@ class Migration(migrations.Migration): | |
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('password', models.CharField(max_length=255)), | ||
('timestamp', models.DateTimeField(auto_now=True)), | ||
('timestamp', models.DateTimeField(default=django.utils.timezone.now)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='password_history', to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# empty for now |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
handle_label
method works fine for one or a handful of users, but doesn't scale nicely for a large userbase or for all users in a system. Should we improve this mechanism or leave be until someone complains?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure of the particulars of the use case driving these changes, but I think it'd be useful to set an expiration for all users if
I don't have a strong opinion on that functionality being required from the get-go, and perhaps a new issue to track that functionality is useful and it can be added later when required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jwegner your first point is handled by the global setting ACCOUNT_PASSWORD_EXPIRY, which is used by default if password expiration is enabled and the user does not have their own PasswordExpiry instance. Good thought on the second case, but I'd prefer to track the idea separately.