Commit d6203b7f by Sven Marnach Committed by GitHub

Merge pull request #13124 from open-craft/smarnach/manage-user

Add support to set initial password hash to manage_user command.
parents 9b48eaf2 0206dfae
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment