diff --git a/src/authentic2_auth_saml/__init__.py b/src/authentic2_auth_saml/__init__.py index 0121e3144..21047a7a2 100644 --- a/src/authentic2_auth_saml/__init__.py +++ b/src/authentic2_auth_saml/__init__.py @@ -13,3 +13,5 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . + +default_app_config = '%s.apps.AppConfig' % __name__ diff --git a/src/authentic2_auth_saml/apps.py b/src/authentic2_auth_saml/apps.py new file mode 100644 index 000000000..067329fbb --- /dev/null +++ b/src/authentic2_auth_saml/apps.py @@ -0,0 +1,42 @@ +# authentic2 - versatile identity manager +# Copyright (C) 2010-2020 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import django.apps + + +class AppConfig(django.apps.AppConfig): + + name = 'authentic2_auth_saml' + + def ready(self): + from django.db.models.signals import pre_save + from authentic2.custom_user.models import DeletedUser + + pre_save.connect( + self.pre_save_deleted_user, + sender=DeletedUser) + + def pre_save_deleted_user(self, sender, instance, **kwargs): + '''Delete and copy UserSamlIdentifier to old_data''' + from mellon.models import UserSAMLIdentifier + + saml_accounts = UserSAMLIdentifier.objects.filter(user__uuid=instance.old_uuid).order_by('id') + for saml_account in saml_accounts: + instance.old_data = instance.old_data or {} + instance.old_data.setdefault('saml_accounts', []).append({ + 'issuer': saml_account.issuer, + 'name_id': saml_account.name_id, + }) diff --git a/tests/test_auth_saml.py b/tests/test_auth_saml.py index 0494b337a..4ac7b1cb8 100644 --- a/tests/test_auth_saml.py +++ b/tests/test_auth_saml.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import datetime import os import re @@ -22,7 +23,12 @@ import pytest import lasso from django.contrib.auth import get_user_model +from django.utils.timezone import now + +from mellon.models import UserSAMLIdentifier + from authentic2.models import Attribute +from authentic2.custom_user.models import DeletedUser from authentic2_auth_saml.adapters import AuthenticAdapter, MappingError User = get_user_model() @@ -262,3 +268,24 @@ def test_login_autorun(db, app, settings): settings.AUTH_FRONTENDS_KWARGS = {'password': {'show_condition': 'remote_addr==\'0.0.0.0\''}} response = app.get('/login/', status=302) assert '/accounts/saml/login/?entityID=' in response['Location'] + + +def test_save_account_on_delete_user(db): + user = User.objects.create() + UserSAMLIdentifier.objects.create(user=user, issuer='https://idp1.com/', name_id='1234') + UserSAMLIdentifier.objects.create(user=user, issuer='https://idp2.com/', name_id='4567') + + user.mark_as_deleted() + User.objects.cleanup(threshold=0, timestamp=now() + datetime.timedelta(seconds=1)) + assert UserSAMLIdentifier.objects.count() == 0 + deleted_user = DeletedUser.objects.get() + assert deleted_user.old_data.get('saml_accounts') == [ + { + 'issuer': 'https://idp1.com/', + 'name_id': '1234', + }, + { + 'issuer': 'https://idp2.com/', + 'name_id': '4567', + } + ]