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',
+ }
+ ]