From 7e013975f70a227256335d7de9cc3396f0137d35 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 3 Nov 2020 09:54:41 +0100 Subject: [PATCH 1/2] misc: set unusable password on federated users (#48136) --- .../migrations/0021_set_unusable_password.py | 29 +++++++++++++++++++ src/authentic2_auth_fc/backends.py | 1 + src/authentic2_auth_oidc/backends.py | 1 + src/authentic2_auth_saml/adapters.py | 5 +++- tests/auth_fc/test_auth_fc.py | 4 ++- tests/test_migrations.py | 14 +++++++++ 6 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/authentic2/custom_user/migrations/0021_set_unusable_password.py diff --git a/src/authentic2/custom_user/migrations/0021_set_unusable_password.py b/src/authentic2/custom_user/migrations/0021_set_unusable_password.py new file mode 100644 index 00000000..688e242e --- /dev/null +++ b/src/authentic2/custom_user/migrations/0021_set_unusable_password.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.29 on 2020-11-02 21:52 +from __future__ import unicode_literals + + +from django.db import migrations +from django.contrib.auth.models import AbstractUser + + +def noop(apps, schema_editor): + pass + + +def set_unusable_password(apps, schema_editor): + User = apps.get_model('custom_user', 'User') + for user in User.objects.filter(password=''): + AbstractUser.set_unusable_password(user) + user.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('custom_user', '0020_deleteduser'), + ] + + operations = [ + migrations.RunPython(set_unusable_password, noop), + ] diff --git a/src/authentic2_auth_fc/backends.py b/src/authentic2_auth_fc/backends.py index 76a90a6b..9d8d4e4a 100644 --- a/src/authentic2_auth_fc/backends.py +++ b/src/authentic2_auth_fc/backends.py @@ -51,6 +51,7 @@ class FcBackend(ModelBackend): if not user and app_settings.create: User = get_user_model() user = User.objects.create(ou=get_default_ou()) + user.set_unusable_password() try: models.FcAccount.objects.create( user=user, diff --git a/src/authentic2_auth_oidc/backends.py b/src/authentic2_auth_oidc/backends.py index d3666019..7181e1c2 100644 --- a/src/authentic2_auth_oidc/backends.py +++ b/src/authentic2_auth_oidc/backends.py @@ -241,6 +241,7 @@ class OIDCBackend(ModelBackend): pass if not user: user = User.objects.create(ou=provider.ou) + user.set_unusable_password() created = True oidc_account, created = models.OIDCAccount.objects.get_or_create( provider=provider, diff --git a/src/authentic2_auth_saml/adapters.py b/src/authentic2_auth_saml/adapters.py index a5dbdbb1..87c57beb 100644 --- a/src/authentic2_auth_saml/adapters.py +++ b/src/authentic2_auth_saml/adapters.py @@ -65,7 +65,10 @@ class SamlConditionContextProxy(object): class AuthenticAdapter(DefaultAdapter): def create_user(self, user_class): - return user_class.objects.create() + user = user_class() + user.set_unusable_password() + user.save() + return user def finish_create_user(self, idp, saml_attributes, user): try: diff --git a/tests/auth_fc/test_auth_fc.py b/tests/auth_fc/test_auth_fc.py index b3da8d7d..88ac18ee 100644 --- a/tests/auth_fc/test_auth_fc.py +++ b/tests/auth_fc/test_auth_fc.py @@ -203,7 +203,9 @@ def test_requests_proxies_support(settings, app): def test_no_password_with_fc_account_can_reset_password(app, db, mailoutbox): - user = User.objects.create(email='john.doe@example.com') + user = User(email='john.doe@example.com') + user.set_unusable_password() + user.save() # No FC account, forbidden to set a password response = app.get('/login/') response = response.click('Reset it!').maybe_follow() diff --git a/tests/test_migrations.py b/tests/test_migrations.py index 86b12ff9..57ce0b44 100644 --- a/tests/test_migrations.py +++ b/tests/test_migrations.py @@ -16,6 +16,7 @@ import mock +from django.contrib.auth.models import AbstractUser from django.db.utils import ProgrammingError @@ -49,3 +50,16 @@ def test_migration_0028_trigram_unaccent_index(transactional_db, migration): with mock.patch('django.db.backends.postgresql.schema.DatabaseSchemaEditor.execute') as mocked: mocked.side_effect = programming_error migration.apply([('authentic2', '0028_trigram_unaccent_index')]) + + +def test_migration_custom_user_0021_set_unusable_password(transactional_db, migration): + old_apps = migration.before([('custom_user', '0020_deleteduser')]) + + User = old_apps.get_model('custom_user', 'User') + user = User.objects.create() + assert user.password == '' + + new_apps = migration.apply([('custom_user', '0021_set_unusable_password')]) + User = new_apps.get_model('custom_user', 'User') + user = User.objects.get() + assert not AbstractUser.has_usable_password(user) -- 2.29.1