Add support to set initial password hash to manage_user command.
This commit is contained in:
@@ -4,6 +4,7 @@ Django users, set/unset permission bits, and associate groups by name.
|
||||
"""
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.hashers import is_password_usable
|
||||
from django.contrib.auth.models import Group, BaseUserManager
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
@@ -24,6 +25,7 @@ class Command(BaseCommand):
|
||||
parser.add_argument('--superuser', dest='is_superuser', action='store_true')
|
||||
parser.add_argument('--staff', dest='is_staff', action='store_true')
|
||||
parser.add_argument('--unusable-password', dest='unusable_password', action='store_true')
|
||||
parser.add_argument('--initial-password-hash', dest='initial_password_hash')
|
||||
parser.add_argument('-g', '--groups', nargs='*', default=[])
|
||||
|
||||
def _maybe_update(self, user, attribute, new_value):
|
||||
@@ -69,7 +71,8 @@ class Command(BaseCommand):
|
||||
user.delete()
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, username, email, is_remove, is_staff, is_superuser, groups, unusable_password, *args, **options):
|
||||
def handle(self, username, email, is_remove, is_staff, is_superuser, groups,
|
||||
unusable_password, initial_password_hash, *args, **options):
|
||||
|
||||
if is_remove:
|
||||
return self._handle_remove(username, email)
|
||||
@@ -81,10 +84,15 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
if created:
|
||||
# Set the password to a random, unknown, but usable password
|
||||
# allowing self-service password resetting. Cases where unusable
|
||||
# passwords are required, should be explicit, and will be handled below.
|
||||
user.set_password(BaseUserManager().make_random_password(25))
|
||||
if initial_password_hash:
|
||||
if not is_password_usable(initial_password_hash):
|
||||
raise CommandError('The password hash provided for user {} is invalid.'.format(username))
|
||||
user.password = initial_password_hash
|
||||
else:
|
||||
# Set the password to a random, unknown, but usable password
|
||||
# allowing self-service password resetting. Cases where unusable
|
||||
# passwords are required, should be explicit, and will be handled below.
|
||||
user.set_password(BaseUserManager().make_random_password(25))
|
||||
self.stderr.write(_('Created new user: "{}"').format(user))
|
||||
else:
|
||||
# NOTE, we will not update the email address of an existing user.
|
||||
|
||||
@@ -4,6 +4,7 @@ Unit tests for user_management management commands.
|
||||
import itertools
|
||||
|
||||
import ddt
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.core.management import call_command, CommandError
|
||||
from django.test import TestCase
|
||||
@@ -71,6 +72,33 @@ class TestManageUserCommand(TestCase):
|
||||
call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--unusable-password')
|
||||
self.assertFalse(user.has_usable_password())
|
||||
|
||||
def test_initial_password_hash(self):
|
||||
"""
|
||||
Ensure that a user's password hash is set correctly when the user is created,
|
||||
and that it isn't touched for existing users.
|
||||
"""
|
||||
initial_hash = make_password('hunter2')
|
||||
|
||||
# Make sure the command aborts if the provided hash isn't a valid Django password hash
|
||||
with self.assertRaises(CommandError) as exc_context:
|
||||
call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--initial-password-hash', 'invalid_hash')
|
||||
self.assertIn('password hash', str(exc_context.exception).lower())
|
||||
|
||||
# Make sure the hash gets set correctly for a new user
|
||||
call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--initial-password-hash', initial_hash)
|
||||
user = User.objects.get(username=TEST_USERNAME)
|
||||
self.assertEqual(user.password, initial_hash)
|
||||
|
||||
# Change the password
|
||||
new_hash = make_password('correct horse battery staple')
|
||||
user.password = new_hash
|
||||
user.save()
|
||||
|
||||
# Verify that calling manage_user again leaves the password untouched
|
||||
call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--initial-password-hash', initial_hash)
|
||||
user = User.objects.get(username=TEST_USERNAME)
|
||||
self.assertEqual(user.password, new_hash)
|
||||
|
||||
def test_wrong_email(self):
|
||||
"""
|
||||
Ensure that the operation is aborted if the username matches an
|
||||
|
||||
Reference in New Issue
Block a user