From 6c231ae2b97d718a36f899eb19a3a1de1364c44e Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 6 Oct 2020 13:49:46 +0200 Subject: [PATCH] misc: prevent cleaning of unused LDAP and OIDC accounts (#47387) --- .../commands/clean-unused-accounts.py | 12 +++++- tests/test_commands.py | 40 ++++++++++++++----- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/authentic2/management/commands/clean-unused-accounts.py b/src/authentic2/management/commands/clean-unused-accounts.py index bc0a93f9..b67732ea 100644 --- a/src/authentic2/management/commands/clean-unused-accounts.py +++ b/src/authentic2/management/commands/clean-unused-accounts.py @@ -27,6 +27,7 @@ from django.utils import timezone, translation from django.utils.six.moves.urllib import parse as urlparse from django_rbac.utils import get_ou_model +from authentic2.backends.ldap_backend import LDAPBackend from authentic2.utils import send_templated_mail from django.conf import settings @@ -61,6 +62,15 @@ class Command(BaseCommand): logger.propagate = False self.now = timezone.now() + + # exclude user from LDAP directories based on their source name (or realm) + realms = [block['realm'] for block in LDAPBackend.get_config() if block.get('realm')] + self.user_qs = ( + User.objects.all() + .exclude(oidc_account__isnull=False) + .exclude(userexternalid__source__in=realms) + ) + translation.activate(settings.LANGUAGE_CODE) try: self.clean_unused_accounts() @@ -71,7 +81,7 @@ class Command(BaseCommand): for ou in get_ou_model().objects.filter(clean_unused_accounts_alert__isnull=False): alert_delay = timedelta(days=ou.clean_unused_accounts_alert) deletion_delay = timedelta(days=ou.clean_unused_accounts_deletion) - ou_users = User.objects.filter(ou=ou) + ou_users = self.user_qs.filter(ou=ou) # reset last_account_deletion_alert for users which connected since last alert active_users = ou_users.filter(last_login__gte=F('last_account_deletion_alert')) diff --git a/tests/test_commands.py b/tests/test_commands.py index b4f35fb6..838ad100 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -26,7 +26,8 @@ from django.utils.timezone import now import py from authentic2.a2_rbac.utils import get_default_ou -from authentic2_auth_oidc.models import OIDCProvider +from authentic2.models import UserExternalId +from authentic2_auth_oidc.models import OIDCProvider, OIDCAccount from django_rbac.models import ADMIN_OP from django_rbac.models import Operation from django_rbac.utils import get_operation @@ -37,6 +38,8 @@ from django.contrib.auth import get_user_model from .utils import login, call_command +User = get_user_model() + if six.PY2: FileType = file # noqa: F821 else: @@ -57,30 +60,50 @@ def test_changepassword(db, simple_user, monkeypatch): assert old_pass != simple_user.password -def test_clean_unused_account(db, simple_user, mailoutbox, freezer): +def test_clean_unused_account(db, simple_user, mailoutbox, freezer, settings): + settings.LDAP_AUTH_SETTINGS = [{'realm': 'ldap', 'url': 'ldap://ldap.com/', 'basedn': 'dc=ldap,dc=com'}] + ldap_user = User.objects.create(username='ldap-user', + email='ldap-user@example.com', + ou=simple_user.ou) + oidc_user = User.objects.create(username='oidc-user', + email='oidc-user@example.com', + ou=simple_user.ou) + UserExternalId.objects.create(user=ldap_user, source='ldap', + external_id='whatever') + provider = OIDCProvider.objects.create(name='oidc', ou=simple_user.ou) + OIDCAccount.objects.create(user=oidc_user, provider=provider, sub='1') + email = simple_user.email freezer.move_to('2018-01-01') simple_user.ou.clean_unused_accounts_alert = 2 simple_user.ou.clean_unused_accounts_deletion = 3 simple_user.ou.save() - simple_user.last_login = now() - datetime.timedelta(days=2) - simple_user.save() + last_login = now() - datetime.timedelta(days=2, seconds=30) + for user in (simple_user, ldap_user, oidc_user): + user.last_login = last_login + user.save() call_command('clean-unused-accounts') - simple_user.refresh_from_db() - assert not simple_user.deleted + + for user in (simple_user, ldap_user, oidc_user): + user.refresh_from_db() + assert not simple_user.deleted assert len(mailoutbox) == 1 freezer.move_to('2018-01-01 12:00:00') # no new mail, no deletion call_command('clean-unused-accounts') - simple_user.refresh_from_db() - assert not simple_user.deleted + for user in (simple_user, ldap_user, oidc_user): + user.refresh_from_db() + assert not simple_user.deleted assert len(mailoutbox) == 1 freezer.move_to('2018-01-02') call_command('clean-unused-accounts') + for user in (ldap_user, oidc_user): + user.refresh_from_db() + assert not simple_user.deleted simple_user.refresh_from_db() assert simple_user.deleted assert len(mailoutbox) == 2 @@ -318,7 +341,6 @@ def test_check_identifiers_uniqueness(db, capsys, settings): settings.A2_EMAIL_IS_UNIQUE = False settings.A2_USERNAME_IS_UNIQUE = False - User = get_user_model() user1 = User.objects.create( username='foo', email='foo@example.net', first_name='Toto', last_name='Foo') -- 2.28.0