diff --git a/common/djangoapps/student/management/commands/manage_user.py b/common/djangoapps/student/management/commands/manage_user.py index dcb299006e..fed69c7771 100644 --- a/common/djangoapps/student/management/commands/manage_user.py +++ b/common/djangoapps/student/management/commands/manage_user.py @@ -23,6 +23,7 @@ class Command(BaseCommand): parser.add_argument('--remove', dest='is_remove', action='store_true') 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('-g', '--groups', nargs='*', default=[]) def _maybe_update(self, user, attribute, new_value): @@ -68,7 +69,7 @@ class Command(BaseCommand): user.delete() @transaction.atomic - def handle(self, username, email, is_remove, is_staff, is_superuser, groups, *args, **options): + def handle(self, username, email, is_remove, is_staff, is_superuser, groups, unusable_password, *args, **options): if is_remove: return self._handle_remove(username, email) @@ -91,6 +92,11 @@ class Command(BaseCommand): self._maybe_update(user, 'is_staff', is_staff) self._maybe_update(user, 'is_superuser', is_superuser) + # Set unusable password if specified + if unusable_password and user.has_usable_password(): + self.stderr.write(_('Setting unusable password for user "{}"').format(user)) + user.set_unusable_password() + # Ensure the user has a profile try: __ = user.profile diff --git a/common/djangoapps/student/management/tests/test_manage_user.py b/common/djangoapps/student/management/tests/test_manage_user.py index 1335ee5b14..3b3186e250 100644 --- a/common/djangoapps/student/management/tests/test_manage_user.py +++ b/common/djangoapps/student/management/tests/test_manage_user.py @@ -48,6 +48,29 @@ class TestManageUserCommand(TestCase): call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--remove') self.assertEqual([], list(User.objects.all())) + def test_unusable_password(self): + """ + Ensure that a user's password is set to an unusable_password. + """ + user = User.objects.create(username=TEST_USERNAME, email=TEST_EMAIL) + self.assertEqual([(TEST_USERNAME, TEST_EMAIL)], [(u.username, u.email) for u in User.objects.all()]) + user.set_password(User.objects.make_random_password()) + user.save() + + # Run once without passing --unusable-password and make sure the password is usable + call_command('manage_user', TEST_USERNAME, TEST_EMAIL) + user = User.objects.get(username=TEST_USERNAME, email=TEST_EMAIL) + self.assertTrue(user.has_usable_password()) + + # Make sure the user now has an unusable_password + call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--unusable-password') + user = User.objects.get(username=TEST_USERNAME, email=TEST_EMAIL) + self.assertFalse(user.has_usable_password()) + + # check idempotency + call_command('manage_user', TEST_USERNAME, TEST_EMAIL, '--unusable-password') + self.assertFalse(user.has_usable_password()) + def test_wrong_email(self): """ Ensure that the operation is aborted if the username matches an