authentik.providers.saml.tests.test_models_session

Test SAMLSession Model

  1"""Test SAMLSession Model"""
  2
  3from datetime import timedelta
  4
  5from django.db import IntegrityError
  6from django.test import TestCase
  7from django.utils import timezone
  8
  9from authentik.common.saml.constants import (
 10    SAML_NAME_ID_FORMAT_EMAIL,
 11)
 12from authentik.core.models import AuthenticatedSession, Session, User
 13from authentik.core.tests.utils import create_test_flow
 14from authentik.lib.generators import generate_id
 15from authentik.providers.saml.api.sessions import SAMLSessionSerializer
 16from authentik.providers.saml.models import SAMLProvider, SAMLSession
 17
 18
 19class TestSAMLSessionModel(TestCase):
 20    """Test SAMLSession model functionality"""
 21
 22    def setUp(self):
 23        """Set up test fixtures"""
 24        self.user = User.objects.create_user(
 25            username="testuser",
 26            email="test@example.com",
 27        )
 28        self.flow = create_test_flow()
 29
 30        # Create a provider
 31        self.provider = SAMLProvider.objects.create(
 32            name="test-provider",
 33            authorization_flow=self.flow,
 34            acs_url="https://sp.example.com/acs",
 35            issuer_override="https://idp.example.com",
 36        )
 37
 38        # Create another provider for testing
 39        self.provider2 = SAMLProvider.objects.create(
 40            name="test-provider-2",
 41            authorization_flow=self.flow,
 42            acs_url="https://sp2.example.com/acs",
 43            issuer_override="https://idp2.example.com",
 44        )
 45
 46        # Create a session first (using authentik's custom Session model)
 47        self.django_session = Session.objects.create(
 48            session_key=generate_id(),
 49            last_ip="127.0.0.1",
 50        )
 51
 52        # Create an authenticated session
 53        self.auth_session = AuthenticatedSession.objects.create(
 54            session=self.django_session,
 55            user=self.user,
 56        )
 57
 58        # Session data
 59        self.session_index = generate_id()
 60        self.name_id = "test@example.com"
 61        self.name_id_format = SAML_NAME_ID_FORMAT_EMAIL
 62        self.expires = timezone.now() + timedelta(hours=8)
 63
 64    def test_session_creation(self):
 65        """Test creating a SAML session"""
 66        saml_session = SAMLSession.objects.create(
 67            provider=self.provider,
 68            user=self.user,
 69            session=self.auth_session,
 70            session_index=self.session_index,
 71            name_id=self.name_id,
 72            name_id_format=self.name_id_format,
 73            expires=self.expires,
 74            expiring=True,
 75            issuer="authentik",
 76        )
 77
 78        # Verify the session was created
 79        self.assertIsNotNone(saml_session.pk)
 80        self.assertEqual(saml_session.provider, self.provider)
 81        self.assertEqual(saml_session.user, self.user)
 82        self.assertEqual(saml_session.session, self.auth_session)
 83        self.assertEqual(saml_session.session_index, self.session_index)
 84        self.assertEqual(saml_session.name_id, self.name_id)
 85        self.assertEqual(saml_session.name_id_format, self.name_id_format)
 86        self.assertIsNotNone(saml_session.created)
 87
 88        # Test string representation
 89        expected_str = f"SAML Session for provider {self.provider.pk} and user {self.user.pk}"
 90        self.assertEqual(str(saml_session), expected_str)
 91
 92    def test_unique_constraint_session_index_provider(self):
 93        """Test that session_index must be unique per provider"""
 94        # Create first session
 95        SAMLSession.objects.create(
 96            provider=self.provider,
 97            user=self.user,
 98            session=self.auth_session,
 99            session_index=self.session_index,
100            name_id=self.name_id,
101            name_id_format=self.name_id_format,
102            expires=self.expires,
103            expiring=True,
104            issuer="authentik",
105        )
106
107        # Try to create another session with same session_index and provider
108        with self.assertRaises(IntegrityError):
109            SAMLSession.objects.create(
110                provider=self.provider,
111                user=self.user,
112                session=self.auth_session,
113                session_index=self.session_index,  # Same session_index
114                name_id="different@example.com",
115                name_id_format=self.name_id_format,
116                expires=self.expires,
117                expiring=True,
118                issuer="authentik",
119            )
120
121    def test_cascade_deletion_user(self):
122        """Test that deleting a user deletes associated SAML sessions"""
123        # Create SAML session
124        saml_session = SAMLSession.objects.create(
125            provider=self.provider,
126            user=self.user,
127            session=self.auth_session,
128            session_index=self.session_index,
129            name_id=self.name_id,
130            name_id_format=self.name_id_format,
131            expires=self.expires,
132            expiring=True,
133            issuer="authentik",
134        )
135
136        # Verify session exists
137        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
138
139        # Delete the user
140        self.user.delete()
141
142        # Verify SAML session was deleted
143        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
144
145    def test_cascade_deletion_provider(self):
146        """Test that deleting a provider deletes associated SAML sessions"""
147        # Create SAML session
148        saml_session = SAMLSession.objects.create(
149            provider=self.provider,
150            user=self.user,
151            session=self.auth_session,
152            session_index=self.session_index,
153            name_id=self.name_id,
154            name_id_format=self.name_id_format,
155            expires=self.expires,
156            expiring=True,
157            issuer="authentik",
158        )
159
160        # Verify session exists
161        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
162
163        # Delete the provider
164        self.provider.delete()
165
166        # Verify SAML session was deleted
167        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
168
169    def test_cascade_deletion_authenticated_session(self):
170        """Test that deleting an AuthenticatedSession deletes associated SAML sessions"""
171        # Create SAML session
172        saml_session = SAMLSession.objects.create(
173            provider=self.provider,
174            user=self.user,
175            session=self.auth_session,
176            session_index=self.session_index,
177            name_id=self.name_id,
178            name_id_format=self.name_id_format,
179            expires=self.expires,
180            expiring=True,
181            issuer="authentik",
182        )
183
184        # Verify session exists
185        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
186
187        # Delete the authenticated session
188        self.auth_session.delete()
189
190        # Verify SAML session was deleted
191        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
192
193    def test_multiple_sessions_per_user(self):
194        """Test that a user can have multiple SAML sessions with different providers"""
195        # Create first session
196        session1 = SAMLSession.objects.create(
197            provider=self.provider,
198            user=self.user,
199            session=self.auth_session,
200            session_index=generate_id(),
201            name_id=self.name_id,
202            name_id_format=self.name_id_format,
203            expires=self.expires,
204            expiring=True,
205            issuer="authentik",
206        )
207
208        # Create second session with different provider
209        session2 = SAMLSession.objects.create(
210            provider=self.provider2,
211            user=self.user,
212            session=self.auth_session,
213            session_index=generate_id(),
214            name_id=self.name_id,
215            name_id_format=self.name_id_format,
216            expires=self.expires,
217            expiring=True,
218            issuer="authentik",
219        )
220
221        # Verify both sessions exist
222        user_sessions = SAMLSession.objects.filter(user=self.user)
223        self.assertEqual(user_sessions.count(), 2)
224        self.assertIn(session1, user_sessions)
225        self.assertIn(session2, user_sessions)
226
227    def test_session_expiry_tracking(self):
228        """Test that session expiry time is properly stored"""
229        # Create session with specific expiry
230        future_time = timezone.now() + timedelta(hours=24)
231        saml_session = SAMLSession.objects.create(
232            provider=self.provider,
233            user=self.user,
234            session=self.auth_session,
235            session_index=self.session_index,
236            name_id=self.name_id,
237            name_id_format=self.name_id_format,
238            expires=future_time,
239            expiring=True,
240            issuer="authentik",
241        )
242
243        # Verify expiry time
244        self.assertEqual(saml_session.expires, future_time)
245
246        # Check if session is expired (ExpiringModel behavior)
247        self.assertFalse(saml_session.is_expired)
248
249        # Create an expired session
250        past_time = timezone.now() - timedelta(hours=1)
251        expired_session = SAMLSession.objects.create(
252            provider=self.provider2,
253            user=self.user,
254            session=self.auth_session,
255            session_index=generate_id(),
256            name_id=self.name_id,
257            name_id_format=self.name_id_format,
258            expires=past_time,
259            expiring=True,
260            issuer="authentik",
261        )
262
263        # Check if marked as expired
264        self.assertTrue(expired_session.is_expired)
265
266    def test_name_id_format_optional(self):
267        """Test that name_id_format is optional (can be blank)"""
268        # Create session without name_id_format
269        saml_session = SAMLSession.objects.create(
270            provider=self.provider,
271            user=self.user,
272            session=self.auth_session,
273            session_index=self.session_index,
274            name_id=self.name_id,
275            name_id_format="",  # Blank format
276            expires=self.expires,
277            expiring=True,
278            issuer="authentik",
279        )
280
281        # Verify it was created successfully
282        self.assertIsNotNone(saml_session.pk)
283        self.assertEqual(saml_session.name_id_format, "")
284
285    def test_query_sessions_by_provider(self):
286        """Test querying sessions by provider"""
287        # Create sessions for different providers
288        session1 = SAMLSession.objects.create(
289            provider=self.provider,
290            user=self.user,
291            session=self.auth_session,
292            session_index=generate_id(),
293            name_id=self.name_id,
294            name_id_format=self.name_id_format,
295            expires=self.expires,
296            expiring=True,
297            issuer="authentik",
298        )
299
300        session2 = SAMLSession.objects.create(
301            provider=self.provider2,
302            user=self.user,
303            session=self.auth_session,
304            session_index=generate_id(),
305            name_id=self.name_id,
306            name_id_format=self.name_id_format,
307            expires=self.expires,
308            expiring=True,
309            issuer="authentik",
310        )
311
312        # Query by provider
313        provider1_sessions = SAMLSession.objects.filter(provider=self.provider)
314        self.assertEqual(provider1_sessions.count(), 1)
315        self.assertEqual(provider1_sessions.first(), session1)
316
317        provider2_sessions = SAMLSession.objects.filter(provider=self.provider2)
318        self.assertEqual(provider2_sessions.count(), 1)
319        self.assertEqual(provider2_sessions.first(), session2)
320
321    def test_serializer_property(self):
322        """Test that the serializer property returns the correct serializer"""
323        saml_session = SAMLSession.objects.create(
324            provider=self.provider,
325            user=self.user,
326            session=self.auth_session,
327            session_index=self.session_index,
328            name_id=self.name_id,
329            name_id_format=self.name_id_format,
330            expires=self.expires,
331            expiring=True,
332            issuer="authentik",
333        )
334
335        # Check serializer property
336        self.assertEqual(saml_session.serializer, SAMLSessionSerializer)
337
338    def test_bulk_delete_sessions_for_user(self):
339        """Test bulk deletion of all SAML sessions for a user"""
340        # Create multiple sessions
341        for i in range(3):
342            SAMLSession.objects.create(
343                provider=self.provider if i % 2 == 0 else self.provider2,
344                user=self.user,
345                session=self.auth_session,
346                session_index=generate_id(),
347                name_id=self.name_id,
348                name_id_format=self.name_id_format,
349                expires=self.expires,
350                expiring=True,
351                issuer="authentik",
352            )
353
354        # Verify sessions exist
355        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 3)
356
357        # Delete all sessions for the user
358        deleted_count, _ = SAMLSession.objects.filter(user=self.user).delete()
359
360        # Verify all were deleted
361        self.assertEqual(deleted_count, 3)
362        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 0)
class TestSAMLSessionModel(django.test.testcases.TestCase):
 20class TestSAMLSessionModel(TestCase):
 21    """Test SAMLSession model functionality"""
 22
 23    def setUp(self):
 24        """Set up test fixtures"""
 25        self.user = User.objects.create_user(
 26            username="testuser",
 27            email="test@example.com",
 28        )
 29        self.flow = create_test_flow()
 30
 31        # Create a provider
 32        self.provider = SAMLProvider.objects.create(
 33            name="test-provider",
 34            authorization_flow=self.flow,
 35            acs_url="https://sp.example.com/acs",
 36            issuer_override="https://idp.example.com",
 37        )
 38
 39        # Create another provider for testing
 40        self.provider2 = SAMLProvider.objects.create(
 41            name="test-provider-2",
 42            authorization_flow=self.flow,
 43            acs_url="https://sp2.example.com/acs",
 44            issuer_override="https://idp2.example.com",
 45        )
 46
 47        # Create a session first (using authentik's custom Session model)
 48        self.django_session = Session.objects.create(
 49            session_key=generate_id(),
 50            last_ip="127.0.0.1",
 51        )
 52
 53        # Create an authenticated session
 54        self.auth_session = AuthenticatedSession.objects.create(
 55            session=self.django_session,
 56            user=self.user,
 57        )
 58
 59        # Session data
 60        self.session_index = generate_id()
 61        self.name_id = "test@example.com"
 62        self.name_id_format = SAML_NAME_ID_FORMAT_EMAIL
 63        self.expires = timezone.now() + timedelta(hours=8)
 64
 65    def test_session_creation(self):
 66        """Test creating a SAML session"""
 67        saml_session = SAMLSession.objects.create(
 68            provider=self.provider,
 69            user=self.user,
 70            session=self.auth_session,
 71            session_index=self.session_index,
 72            name_id=self.name_id,
 73            name_id_format=self.name_id_format,
 74            expires=self.expires,
 75            expiring=True,
 76            issuer="authentik",
 77        )
 78
 79        # Verify the session was created
 80        self.assertIsNotNone(saml_session.pk)
 81        self.assertEqual(saml_session.provider, self.provider)
 82        self.assertEqual(saml_session.user, self.user)
 83        self.assertEqual(saml_session.session, self.auth_session)
 84        self.assertEqual(saml_session.session_index, self.session_index)
 85        self.assertEqual(saml_session.name_id, self.name_id)
 86        self.assertEqual(saml_session.name_id_format, self.name_id_format)
 87        self.assertIsNotNone(saml_session.created)
 88
 89        # Test string representation
 90        expected_str = f"SAML Session for provider {self.provider.pk} and user {self.user.pk}"
 91        self.assertEqual(str(saml_session), expected_str)
 92
 93    def test_unique_constraint_session_index_provider(self):
 94        """Test that session_index must be unique per provider"""
 95        # Create first session
 96        SAMLSession.objects.create(
 97            provider=self.provider,
 98            user=self.user,
 99            session=self.auth_session,
100            session_index=self.session_index,
101            name_id=self.name_id,
102            name_id_format=self.name_id_format,
103            expires=self.expires,
104            expiring=True,
105            issuer="authentik",
106        )
107
108        # Try to create another session with same session_index and provider
109        with self.assertRaises(IntegrityError):
110            SAMLSession.objects.create(
111                provider=self.provider,
112                user=self.user,
113                session=self.auth_session,
114                session_index=self.session_index,  # Same session_index
115                name_id="different@example.com",
116                name_id_format=self.name_id_format,
117                expires=self.expires,
118                expiring=True,
119                issuer="authentik",
120            )
121
122    def test_cascade_deletion_user(self):
123        """Test that deleting a user deletes associated SAML sessions"""
124        # Create SAML session
125        saml_session = SAMLSession.objects.create(
126            provider=self.provider,
127            user=self.user,
128            session=self.auth_session,
129            session_index=self.session_index,
130            name_id=self.name_id,
131            name_id_format=self.name_id_format,
132            expires=self.expires,
133            expiring=True,
134            issuer="authentik",
135        )
136
137        # Verify session exists
138        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
139
140        # Delete the user
141        self.user.delete()
142
143        # Verify SAML session was deleted
144        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
145
146    def test_cascade_deletion_provider(self):
147        """Test that deleting a provider deletes associated SAML sessions"""
148        # Create SAML session
149        saml_session = SAMLSession.objects.create(
150            provider=self.provider,
151            user=self.user,
152            session=self.auth_session,
153            session_index=self.session_index,
154            name_id=self.name_id,
155            name_id_format=self.name_id_format,
156            expires=self.expires,
157            expiring=True,
158            issuer="authentik",
159        )
160
161        # Verify session exists
162        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
163
164        # Delete the provider
165        self.provider.delete()
166
167        # Verify SAML session was deleted
168        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
169
170    def test_cascade_deletion_authenticated_session(self):
171        """Test that deleting an AuthenticatedSession deletes associated SAML sessions"""
172        # Create SAML session
173        saml_session = SAMLSession.objects.create(
174            provider=self.provider,
175            user=self.user,
176            session=self.auth_session,
177            session_index=self.session_index,
178            name_id=self.name_id,
179            name_id_format=self.name_id_format,
180            expires=self.expires,
181            expiring=True,
182            issuer="authentik",
183        )
184
185        # Verify session exists
186        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
187
188        # Delete the authenticated session
189        self.auth_session.delete()
190
191        # Verify SAML session was deleted
192        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())
193
194    def test_multiple_sessions_per_user(self):
195        """Test that a user can have multiple SAML sessions with different providers"""
196        # Create first session
197        session1 = SAMLSession.objects.create(
198            provider=self.provider,
199            user=self.user,
200            session=self.auth_session,
201            session_index=generate_id(),
202            name_id=self.name_id,
203            name_id_format=self.name_id_format,
204            expires=self.expires,
205            expiring=True,
206            issuer="authentik",
207        )
208
209        # Create second session with different provider
210        session2 = SAMLSession.objects.create(
211            provider=self.provider2,
212            user=self.user,
213            session=self.auth_session,
214            session_index=generate_id(),
215            name_id=self.name_id,
216            name_id_format=self.name_id_format,
217            expires=self.expires,
218            expiring=True,
219            issuer="authentik",
220        )
221
222        # Verify both sessions exist
223        user_sessions = SAMLSession.objects.filter(user=self.user)
224        self.assertEqual(user_sessions.count(), 2)
225        self.assertIn(session1, user_sessions)
226        self.assertIn(session2, user_sessions)
227
228    def test_session_expiry_tracking(self):
229        """Test that session expiry time is properly stored"""
230        # Create session with specific expiry
231        future_time = timezone.now() + timedelta(hours=24)
232        saml_session = SAMLSession.objects.create(
233            provider=self.provider,
234            user=self.user,
235            session=self.auth_session,
236            session_index=self.session_index,
237            name_id=self.name_id,
238            name_id_format=self.name_id_format,
239            expires=future_time,
240            expiring=True,
241            issuer="authentik",
242        )
243
244        # Verify expiry time
245        self.assertEqual(saml_session.expires, future_time)
246
247        # Check if session is expired (ExpiringModel behavior)
248        self.assertFalse(saml_session.is_expired)
249
250        # Create an expired session
251        past_time = timezone.now() - timedelta(hours=1)
252        expired_session = SAMLSession.objects.create(
253            provider=self.provider2,
254            user=self.user,
255            session=self.auth_session,
256            session_index=generate_id(),
257            name_id=self.name_id,
258            name_id_format=self.name_id_format,
259            expires=past_time,
260            expiring=True,
261            issuer="authentik",
262        )
263
264        # Check if marked as expired
265        self.assertTrue(expired_session.is_expired)
266
267    def test_name_id_format_optional(self):
268        """Test that name_id_format is optional (can be blank)"""
269        # Create session without name_id_format
270        saml_session = SAMLSession.objects.create(
271            provider=self.provider,
272            user=self.user,
273            session=self.auth_session,
274            session_index=self.session_index,
275            name_id=self.name_id,
276            name_id_format="",  # Blank format
277            expires=self.expires,
278            expiring=True,
279            issuer="authentik",
280        )
281
282        # Verify it was created successfully
283        self.assertIsNotNone(saml_session.pk)
284        self.assertEqual(saml_session.name_id_format, "")
285
286    def test_query_sessions_by_provider(self):
287        """Test querying sessions by provider"""
288        # Create sessions for different providers
289        session1 = SAMLSession.objects.create(
290            provider=self.provider,
291            user=self.user,
292            session=self.auth_session,
293            session_index=generate_id(),
294            name_id=self.name_id,
295            name_id_format=self.name_id_format,
296            expires=self.expires,
297            expiring=True,
298            issuer="authentik",
299        )
300
301        session2 = SAMLSession.objects.create(
302            provider=self.provider2,
303            user=self.user,
304            session=self.auth_session,
305            session_index=generate_id(),
306            name_id=self.name_id,
307            name_id_format=self.name_id_format,
308            expires=self.expires,
309            expiring=True,
310            issuer="authentik",
311        )
312
313        # Query by provider
314        provider1_sessions = SAMLSession.objects.filter(provider=self.provider)
315        self.assertEqual(provider1_sessions.count(), 1)
316        self.assertEqual(provider1_sessions.first(), session1)
317
318        provider2_sessions = SAMLSession.objects.filter(provider=self.provider2)
319        self.assertEqual(provider2_sessions.count(), 1)
320        self.assertEqual(provider2_sessions.first(), session2)
321
322    def test_serializer_property(self):
323        """Test that the serializer property returns the correct serializer"""
324        saml_session = SAMLSession.objects.create(
325            provider=self.provider,
326            user=self.user,
327            session=self.auth_session,
328            session_index=self.session_index,
329            name_id=self.name_id,
330            name_id_format=self.name_id_format,
331            expires=self.expires,
332            expiring=True,
333            issuer="authentik",
334        )
335
336        # Check serializer property
337        self.assertEqual(saml_session.serializer, SAMLSessionSerializer)
338
339    def test_bulk_delete_sessions_for_user(self):
340        """Test bulk deletion of all SAML sessions for a user"""
341        # Create multiple sessions
342        for i in range(3):
343            SAMLSession.objects.create(
344                provider=self.provider if i % 2 == 0 else self.provider2,
345                user=self.user,
346                session=self.auth_session,
347                session_index=generate_id(),
348                name_id=self.name_id,
349                name_id_format=self.name_id_format,
350                expires=self.expires,
351                expiring=True,
352                issuer="authentik",
353            )
354
355        # Verify sessions exist
356        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 3)
357
358        # Delete all sessions for the user
359        deleted_count, _ = SAMLSession.objects.filter(user=self.user).delete()
360
361        # Verify all were deleted
362        self.assertEqual(deleted_count, 3)
363        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 0)

Test SAMLSession model functionality

def setUp(self):
23    def setUp(self):
24        """Set up test fixtures"""
25        self.user = User.objects.create_user(
26            username="testuser",
27            email="test@example.com",
28        )
29        self.flow = create_test_flow()
30
31        # Create a provider
32        self.provider = SAMLProvider.objects.create(
33            name="test-provider",
34            authorization_flow=self.flow,
35            acs_url="https://sp.example.com/acs",
36            issuer_override="https://idp.example.com",
37        )
38
39        # Create another provider for testing
40        self.provider2 = SAMLProvider.objects.create(
41            name="test-provider-2",
42            authorization_flow=self.flow,
43            acs_url="https://sp2.example.com/acs",
44            issuer_override="https://idp2.example.com",
45        )
46
47        # Create a session first (using authentik's custom Session model)
48        self.django_session = Session.objects.create(
49            session_key=generate_id(),
50            last_ip="127.0.0.1",
51        )
52
53        # Create an authenticated session
54        self.auth_session = AuthenticatedSession.objects.create(
55            session=self.django_session,
56            user=self.user,
57        )
58
59        # Session data
60        self.session_index = generate_id()
61        self.name_id = "test@example.com"
62        self.name_id_format = SAML_NAME_ID_FORMAT_EMAIL
63        self.expires = timezone.now() + timedelta(hours=8)

Set up test fixtures

def test_session_creation(self):
65    def test_session_creation(self):
66        """Test creating a SAML session"""
67        saml_session = SAMLSession.objects.create(
68            provider=self.provider,
69            user=self.user,
70            session=self.auth_session,
71            session_index=self.session_index,
72            name_id=self.name_id,
73            name_id_format=self.name_id_format,
74            expires=self.expires,
75            expiring=True,
76            issuer="authentik",
77        )
78
79        # Verify the session was created
80        self.assertIsNotNone(saml_session.pk)
81        self.assertEqual(saml_session.provider, self.provider)
82        self.assertEqual(saml_session.user, self.user)
83        self.assertEqual(saml_session.session, self.auth_session)
84        self.assertEqual(saml_session.session_index, self.session_index)
85        self.assertEqual(saml_session.name_id, self.name_id)
86        self.assertEqual(saml_session.name_id_format, self.name_id_format)
87        self.assertIsNotNone(saml_session.created)
88
89        # Test string representation
90        expected_str = f"SAML Session for provider {self.provider.pk} and user {self.user.pk}"
91        self.assertEqual(str(saml_session), expected_str)

Test creating a SAML session

def test_unique_constraint_session_index_provider(self):
 93    def test_unique_constraint_session_index_provider(self):
 94        """Test that session_index must be unique per provider"""
 95        # Create first session
 96        SAMLSession.objects.create(
 97            provider=self.provider,
 98            user=self.user,
 99            session=self.auth_session,
100            session_index=self.session_index,
101            name_id=self.name_id,
102            name_id_format=self.name_id_format,
103            expires=self.expires,
104            expiring=True,
105            issuer="authentik",
106        )
107
108        # Try to create another session with same session_index and provider
109        with self.assertRaises(IntegrityError):
110            SAMLSession.objects.create(
111                provider=self.provider,
112                user=self.user,
113                session=self.auth_session,
114                session_index=self.session_index,  # Same session_index
115                name_id="different@example.com",
116                name_id_format=self.name_id_format,
117                expires=self.expires,
118                expiring=True,
119                issuer="authentik",
120            )

Test that session_index must be unique per provider

def test_cascade_deletion_user(self):
122    def test_cascade_deletion_user(self):
123        """Test that deleting a user deletes associated SAML sessions"""
124        # Create SAML session
125        saml_session = SAMLSession.objects.create(
126            provider=self.provider,
127            user=self.user,
128            session=self.auth_session,
129            session_index=self.session_index,
130            name_id=self.name_id,
131            name_id_format=self.name_id_format,
132            expires=self.expires,
133            expiring=True,
134            issuer="authentik",
135        )
136
137        # Verify session exists
138        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
139
140        # Delete the user
141        self.user.delete()
142
143        # Verify SAML session was deleted
144        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())

Test that deleting a user deletes associated SAML sessions

def test_cascade_deletion_provider(self):
146    def test_cascade_deletion_provider(self):
147        """Test that deleting a provider deletes associated SAML sessions"""
148        # Create SAML session
149        saml_session = SAMLSession.objects.create(
150            provider=self.provider,
151            user=self.user,
152            session=self.auth_session,
153            session_index=self.session_index,
154            name_id=self.name_id,
155            name_id_format=self.name_id_format,
156            expires=self.expires,
157            expiring=True,
158            issuer="authentik",
159        )
160
161        # Verify session exists
162        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
163
164        # Delete the provider
165        self.provider.delete()
166
167        # Verify SAML session was deleted
168        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())

Test that deleting a provider deletes associated SAML sessions

def test_cascade_deletion_authenticated_session(self):
170    def test_cascade_deletion_authenticated_session(self):
171        """Test that deleting an AuthenticatedSession deletes associated SAML sessions"""
172        # Create SAML session
173        saml_session = SAMLSession.objects.create(
174            provider=self.provider,
175            user=self.user,
176            session=self.auth_session,
177            session_index=self.session_index,
178            name_id=self.name_id,
179            name_id_format=self.name_id_format,
180            expires=self.expires,
181            expiring=True,
182            issuer="authentik",
183        )
184
185        # Verify session exists
186        self.assertTrue(SAMLSession.objects.filter(pk=saml_session.pk).exists())
187
188        # Delete the authenticated session
189        self.auth_session.delete()
190
191        # Verify SAML session was deleted
192        self.assertFalse(SAMLSession.objects.filter(pk=saml_session.pk).exists())

Test that deleting an AuthenticatedSession deletes associated SAML sessions

def test_multiple_sessions_per_user(self):
194    def test_multiple_sessions_per_user(self):
195        """Test that a user can have multiple SAML sessions with different providers"""
196        # Create first session
197        session1 = SAMLSession.objects.create(
198            provider=self.provider,
199            user=self.user,
200            session=self.auth_session,
201            session_index=generate_id(),
202            name_id=self.name_id,
203            name_id_format=self.name_id_format,
204            expires=self.expires,
205            expiring=True,
206            issuer="authentik",
207        )
208
209        # Create second session with different provider
210        session2 = SAMLSession.objects.create(
211            provider=self.provider2,
212            user=self.user,
213            session=self.auth_session,
214            session_index=generate_id(),
215            name_id=self.name_id,
216            name_id_format=self.name_id_format,
217            expires=self.expires,
218            expiring=True,
219            issuer="authentik",
220        )
221
222        # Verify both sessions exist
223        user_sessions = SAMLSession.objects.filter(user=self.user)
224        self.assertEqual(user_sessions.count(), 2)
225        self.assertIn(session1, user_sessions)
226        self.assertIn(session2, user_sessions)

Test that a user can have multiple SAML sessions with different providers

def test_session_expiry_tracking(self):
228    def test_session_expiry_tracking(self):
229        """Test that session expiry time is properly stored"""
230        # Create session with specific expiry
231        future_time = timezone.now() + timedelta(hours=24)
232        saml_session = SAMLSession.objects.create(
233            provider=self.provider,
234            user=self.user,
235            session=self.auth_session,
236            session_index=self.session_index,
237            name_id=self.name_id,
238            name_id_format=self.name_id_format,
239            expires=future_time,
240            expiring=True,
241            issuer="authentik",
242        )
243
244        # Verify expiry time
245        self.assertEqual(saml_session.expires, future_time)
246
247        # Check if session is expired (ExpiringModel behavior)
248        self.assertFalse(saml_session.is_expired)
249
250        # Create an expired session
251        past_time = timezone.now() - timedelta(hours=1)
252        expired_session = SAMLSession.objects.create(
253            provider=self.provider2,
254            user=self.user,
255            session=self.auth_session,
256            session_index=generate_id(),
257            name_id=self.name_id,
258            name_id_format=self.name_id_format,
259            expires=past_time,
260            expiring=True,
261            issuer="authentik",
262        )
263
264        # Check if marked as expired
265        self.assertTrue(expired_session.is_expired)

Test that session expiry time is properly stored

def test_name_id_format_optional(self):
267    def test_name_id_format_optional(self):
268        """Test that name_id_format is optional (can be blank)"""
269        # Create session without name_id_format
270        saml_session = SAMLSession.objects.create(
271            provider=self.provider,
272            user=self.user,
273            session=self.auth_session,
274            session_index=self.session_index,
275            name_id=self.name_id,
276            name_id_format="",  # Blank format
277            expires=self.expires,
278            expiring=True,
279            issuer="authentik",
280        )
281
282        # Verify it was created successfully
283        self.assertIsNotNone(saml_session.pk)
284        self.assertEqual(saml_session.name_id_format, "")

Test that name_id_format is optional (can be blank)

def test_query_sessions_by_provider(self):
286    def test_query_sessions_by_provider(self):
287        """Test querying sessions by provider"""
288        # Create sessions for different providers
289        session1 = SAMLSession.objects.create(
290            provider=self.provider,
291            user=self.user,
292            session=self.auth_session,
293            session_index=generate_id(),
294            name_id=self.name_id,
295            name_id_format=self.name_id_format,
296            expires=self.expires,
297            expiring=True,
298            issuer="authentik",
299        )
300
301        session2 = SAMLSession.objects.create(
302            provider=self.provider2,
303            user=self.user,
304            session=self.auth_session,
305            session_index=generate_id(),
306            name_id=self.name_id,
307            name_id_format=self.name_id_format,
308            expires=self.expires,
309            expiring=True,
310            issuer="authentik",
311        )
312
313        # Query by provider
314        provider1_sessions = SAMLSession.objects.filter(provider=self.provider)
315        self.assertEqual(provider1_sessions.count(), 1)
316        self.assertEqual(provider1_sessions.first(), session1)
317
318        provider2_sessions = SAMLSession.objects.filter(provider=self.provider2)
319        self.assertEqual(provider2_sessions.count(), 1)
320        self.assertEqual(provider2_sessions.first(), session2)

Test querying sessions by provider

def test_serializer_property(self):
322    def test_serializer_property(self):
323        """Test that the serializer property returns the correct serializer"""
324        saml_session = SAMLSession.objects.create(
325            provider=self.provider,
326            user=self.user,
327            session=self.auth_session,
328            session_index=self.session_index,
329            name_id=self.name_id,
330            name_id_format=self.name_id_format,
331            expires=self.expires,
332            expiring=True,
333            issuer="authentik",
334        )
335
336        # Check serializer property
337        self.assertEqual(saml_session.serializer, SAMLSessionSerializer)

Test that the serializer property returns the correct serializer

def test_bulk_delete_sessions_for_user(self):
339    def test_bulk_delete_sessions_for_user(self):
340        """Test bulk deletion of all SAML sessions for a user"""
341        # Create multiple sessions
342        for i in range(3):
343            SAMLSession.objects.create(
344                provider=self.provider if i % 2 == 0 else self.provider2,
345                user=self.user,
346                session=self.auth_session,
347                session_index=generate_id(),
348                name_id=self.name_id,
349                name_id_format=self.name_id_format,
350                expires=self.expires,
351                expiring=True,
352                issuer="authentik",
353            )
354
355        # Verify sessions exist
356        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 3)
357
358        # Delete all sessions for the user
359        deleted_count, _ = SAMLSession.objects.filter(user=self.user).delete()
360
361        # Verify all were deleted
362        self.assertEqual(deleted_count, 3)
363        self.assertEqual(SAMLSession.objects.filter(user=self.user).count(), 0)

Test bulk deletion of all SAML sessions for a user