authentik.providers.saml.tests.test_logout_processor_and_parser

Integration tests for SAML Logout - Testing processor and parser together

  1"""Integration tests for SAML Logout - Testing processor and parser together"""
  2
  3from urllib.parse import parse_qs, urlparse
  4
  5from django.test import TestCase
  6
  7from authentik.common.saml.constants import (
  8    RSA_SHA256,
  9    SAML_NAME_ID_FORMAT_EMAIL,
 10)
 11from authentik.core.tests.utils import create_test_cert, create_test_flow
 12from authentik.providers.saml.models import SAMLProvider
 13from authentik.providers.saml.processors.logout_request import LogoutRequestProcessor
 14from authentik.providers.saml.processors.logout_request_parser import LogoutRequestParser
 15
 16
 17class TestLogoutIntegration(TestCase):
 18    """Integration tests for SAML Logout - processor and parser working together"""
 19
 20    def setUp(self):
 21        """Set up test fixtures"""
 22        self.flow = create_test_flow()
 23        self.keypair = create_test_cert()
 24
 25        # Create provider
 26        self.provider = SAMLProvider.objects.create(
 27            name="test-provider",
 28            authorization_flow=self.flow,
 29            acs_url="https://sp.example.com/acs",
 30            sls_url="https://sp.example.com/sls",
 31            issuer="https://idp.example.com",
 32            sp_binding="redirect",
 33            sls_binding="redirect",
 34            signature_algorithm=RSA_SHA256,
 35        )
 36
 37        # Create processor
 38        self.processor = LogoutRequestProcessor(
 39            provider=self.provider,
 40            user=None,
 41            destination="https://sp.example.com/sls",
 42            name_id="test@example.com",
 43            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
 44            session_index="test-session-123",
 45            relay_state="https://idp.example.com/flow/return",
 46        )
 47
 48        # Create parser for validation
 49        self.parser = LogoutRequestParser(self.provider)
 50
 51    def test_post_binding_roundtrip(self):
 52        """Test that a POST-encoded request can be parsed correctly"""
 53        # Generate the request
 54        encoded = self.processor.encode_post()
 55
 56        # Parse it back
 57        parsed = self.parser.parse(encoded)
 58
 59        # Verify all fields match
 60        self.assertEqual(parsed.issuer, self.provider.issuer)
 61        self.assertEqual(parsed.name_id, "test@example.com")
 62        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
 63        self.assertEqual(parsed.session_index, "test-session-123")
 64        self.assertIsNotNone(parsed.id)
 65
 66    def test_redirect_binding_roundtrip(self):
 67        """Test that a redirect-encoded request can be parsed correctly"""
 68        # Generate the request
 69        encoded = self.processor.encode_redirect()
 70
 71        # Parse it back using detached method
 72        parsed = self.parser.parse_detached(encoded)
 73
 74        # Verify all fields match
 75        self.assertEqual(parsed.issuer, self.provider.issuer)
 76        self.assertEqual(parsed.name_id, "test@example.com")
 77        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
 78        self.assertEqual(parsed.session_index, "test-session-123")
 79        self.assertIsNotNone(parsed.id)
 80
 81    def test_signed_post_binding_roundtrip(self):
 82        """Test that a signed POST request can be parsed and verified"""
 83        # Enable signing
 84        self.provider.signing_kp = self.keypair
 85        self.provider.sign_logout_request = True
 86        self.provider.save()
 87
 88        # Create new processor with signing
 89        processor = LogoutRequestProcessor(
 90            provider=self.provider,
 91            user=None,
 92            destination="https://sp.example.com/sls",
 93            name_id="signed@example.com",
 94            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
 95            session_index="signed-session-456",
 96            relay_state="https://idp.example.com/flow/signed",
 97        )
 98
 99        # Generate signed request
100        encoded = processor.encode_post()
101
102        # Create parser with verification enabled
103        parser = LogoutRequestParser(self.provider)
104
105        # Parse it - this would validate signature if verification is enabled
106        parsed = parser.parse(encoded)
107
108        # Verify all fields match
109        self.assertEqual(parsed.issuer, self.provider.issuer)
110        self.assertEqual(parsed.name_id, "signed@example.com")
111        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
112        self.assertEqual(parsed.session_index, "signed-session-456")
113
114    def test_redirect_url_can_be_parsed(self):
115        """Test that the redirect URL contains parseable parameters"""
116        # Generate redirect URL
117        url = self.processor.get_redirect_url()
118
119        # Parse URL and extract SAMLRequest
120        parsed_url = urlparse(url)
121        params = parse_qs(parsed_url.query)
122
123        # Parse the SAMLRequest
124        saml_request = params["SAMLRequest"][0]
125        parsed = self.parser.parse_detached(saml_request)
126
127        # Verify parsing succeeded
128        self.assertEqual(parsed.issuer, self.provider.issuer)
129        self.assertEqual(parsed.name_id, "test@example.com")
130        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
131
132    def test_signed_redirect_url_parameters(self):
133        """Test that signed redirect URL has all required parameters for validation"""
134        # Enable signing
135        self.provider.signing_kp = self.keypair
136        self.provider.sign_logout_request = True
137        self.provider.save()
138
139        processor = LogoutRequestProcessor(
140            provider=self.provider,
141            user=None,
142            destination="https://sp.example.com/sls",
143            name_id="test@example.com",
144            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
145            session_index="test-session",
146            relay_state="https://idp.example.com/return",
147        )
148
149        # Generate signed redirect URL
150        url = processor.get_redirect_url()
151
152        # Parse URL
153        parsed_url = urlparse(url)
154        params = parse_qs(parsed_url.query)
155
156        # Verify all required parameters are present
157        self.assertIn("SAMLRequest", params)
158        self.assertIn("RelayState", params)
159        self.assertIn("SigAlg", params)
160        self.assertIn("Signature", params)
161
162        # Verify signature algorithm matches provider configuration
163        self.assertEqual(params["SigAlg"][0], RSA_SHA256)
164
165        # Parse the SAMLRequest (unsigned XML)
166        parsed = self.parser.parse_detached(params["SAMLRequest"][0])
167        self.assertEqual(parsed.issuer, self.provider.issuer)
168
169    def test_form_data_can_be_parsed(self):
170        """Test that form data generates parseable POST request"""
171        # Get form data
172        form_data = self.processor.get_post_form_data()
173
174        # Parse the SAMLRequest from form data
175        parsed = self.parser.parse(form_data["SAMLRequest"])
176
177        # Verify parsing succeeded
178        self.assertEqual(parsed.issuer, self.provider.issuer)
179        self.assertEqual(parsed.name_id, "test@example.com")
180        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
181        self.assertEqual(parsed.session_index, "test-session-123")
182
183    def test_processor_without_optional_fields(self):
184        """Test integration when optional fields are missing"""
185        # Create processor without session_index and relay_state
186        processor = LogoutRequestProcessor(
187            provider=self.provider,
188            user=None,
189            destination="https://sp.example.com/sls",
190            name_id="minimal@example.com",
191            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
192            session_index=None,
193            relay_state=None,
194        )
195
196        # Test POST binding
197        encoded_post = processor.encode_post()
198        parsed_post = self.parser.parse(encoded_post)
199        self.assertEqual(parsed_post.name_id, "minimal@example.com")
200        self.assertIsNone(parsed_post.session_index)
201
202        # Test redirect binding
203        encoded_redirect = processor.encode_redirect()
204        parsed_redirect = self.parser.parse_detached(encoded_redirect)
205        self.assertEqual(parsed_redirect.name_id, "minimal@example.com")
206        self.assertIsNone(parsed_redirect.session_index)
207
208    def test_multiple_processors_same_provider(self):
209        """Test that multiple processors can use the same provider"""
210        # Create multiple processors with different data
211        processor1 = LogoutRequestProcessor(
212            provider=self.provider,
213            user=None,
214            destination="https://sp1.example.com/sls",
215            name_id="user1@example.com",
216            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
217            session_index="session-1",
218            relay_state="https://idp.example.com/flow1",
219        )
220
221        processor2 = LogoutRequestProcessor(
222            provider=self.provider,
223            user=None,
224            destination="https://sp2.example.com/sls",
225            name_id="user2@example.com",
226            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
227            session_index="session-2",
228            relay_state="https://idp.example.com/flow2",
229        )
230
231        # Generate requests
232        encoded1 = processor1.encode_post()
233        encoded2 = processor2.encode_post()
234
235        # Parse both with same parser
236        parsed1 = self.parser.parse(encoded1)
237        parsed2 = self.parser.parse(encoded2)
238
239        # Verify they have different data
240        self.assertEqual(parsed1.name_id, "user1@example.com")
241        self.assertEqual(parsed2.name_id, "user2@example.com")
242        self.assertEqual(parsed1.session_index, "session-1")
243        self.assertEqual(parsed2.session_index, "session-2")
244
245        # But same issuer
246        self.assertEqual(parsed1.issuer, parsed2.issuer)
247        self.assertEqual(parsed1.issuer, self.provider.issuer)
class TestLogoutIntegration(django.test.testcases.TestCase):
 18class TestLogoutIntegration(TestCase):
 19    """Integration tests for SAML Logout - processor and parser working together"""
 20
 21    def setUp(self):
 22        """Set up test fixtures"""
 23        self.flow = create_test_flow()
 24        self.keypair = create_test_cert()
 25
 26        # Create provider
 27        self.provider = SAMLProvider.objects.create(
 28            name="test-provider",
 29            authorization_flow=self.flow,
 30            acs_url="https://sp.example.com/acs",
 31            sls_url="https://sp.example.com/sls",
 32            issuer="https://idp.example.com",
 33            sp_binding="redirect",
 34            sls_binding="redirect",
 35            signature_algorithm=RSA_SHA256,
 36        )
 37
 38        # Create processor
 39        self.processor = LogoutRequestProcessor(
 40            provider=self.provider,
 41            user=None,
 42            destination="https://sp.example.com/sls",
 43            name_id="test@example.com",
 44            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
 45            session_index="test-session-123",
 46            relay_state="https://idp.example.com/flow/return",
 47        )
 48
 49        # Create parser for validation
 50        self.parser = LogoutRequestParser(self.provider)
 51
 52    def test_post_binding_roundtrip(self):
 53        """Test that a POST-encoded request can be parsed correctly"""
 54        # Generate the request
 55        encoded = self.processor.encode_post()
 56
 57        # Parse it back
 58        parsed = self.parser.parse(encoded)
 59
 60        # Verify all fields match
 61        self.assertEqual(parsed.issuer, self.provider.issuer)
 62        self.assertEqual(parsed.name_id, "test@example.com")
 63        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
 64        self.assertEqual(parsed.session_index, "test-session-123")
 65        self.assertIsNotNone(parsed.id)
 66
 67    def test_redirect_binding_roundtrip(self):
 68        """Test that a redirect-encoded request can be parsed correctly"""
 69        # Generate the request
 70        encoded = self.processor.encode_redirect()
 71
 72        # Parse it back using detached method
 73        parsed = self.parser.parse_detached(encoded)
 74
 75        # Verify all fields match
 76        self.assertEqual(parsed.issuer, self.provider.issuer)
 77        self.assertEqual(parsed.name_id, "test@example.com")
 78        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
 79        self.assertEqual(parsed.session_index, "test-session-123")
 80        self.assertIsNotNone(parsed.id)
 81
 82    def test_signed_post_binding_roundtrip(self):
 83        """Test that a signed POST request can be parsed and verified"""
 84        # Enable signing
 85        self.provider.signing_kp = self.keypair
 86        self.provider.sign_logout_request = True
 87        self.provider.save()
 88
 89        # Create new processor with signing
 90        processor = LogoutRequestProcessor(
 91            provider=self.provider,
 92            user=None,
 93            destination="https://sp.example.com/sls",
 94            name_id="signed@example.com",
 95            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
 96            session_index="signed-session-456",
 97            relay_state="https://idp.example.com/flow/signed",
 98        )
 99
100        # Generate signed request
101        encoded = processor.encode_post()
102
103        # Create parser with verification enabled
104        parser = LogoutRequestParser(self.provider)
105
106        # Parse it - this would validate signature if verification is enabled
107        parsed = parser.parse(encoded)
108
109        # Verify all fields match
110        self.assertEqual(parsed.issuer, self.provider.issuer)
111        self.assertEqual(parsed.name_id, "signed@example.com")
112        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
113        self.assertEqual(parsed.session_index, "signed-session-456")
114
115    def test_redirect_url_can_be_parsed(self):
116        """Test that the redirect URL contains parseable parameters"""
117        # Generate redirect URL
118        url = self.processor.get_redirect_url()
119
120        # Parse URL and extract SAMLRequest
121        parsed_url = urlparse(url)
122        params = parse_qs(parsed_url.query)
123
124        # Parse the SAMLRequest
125        saml_request = params["SAMLRequest"][0]
126        parsed = self.parser.parse_detached(saml_request)
127
128        # Verify parsing succeeded
129        self.assertEqual(parsed.issuer, self.provider.issuer)
130        self.assertEqual(parsed.name_id, "test@example.com")
131        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
132
133    def test_signed_redirect_url_parameters(self):
134        """Test that signed redirect URL has all required parameters for validation"""
135        # Enable signing
136        self.provider.signing_kp = self.keypair
137        self.provider.sign_logout_request = True
138        self.provider.save()
139
140        processor = LogoutRequestProcessor(
141            provider=self.provider,
142            user=None,
143            destination="https://sp.example.com/sls",
144            name_id="test@example.com",
145            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
146            session_index="test-session",
147            relay_state="https://idp.example.com/return",
148        )
149
150        # Generate signed redirect URL
151        url = processor.get_redirect_url()
152
153        # Parse URL
154        parsed_url = urlparse(url)
155        params = parse_qs(parsed_url.query)
156
157        # Verify all required parameters are present
158        self.assertIn("SAMLRequest", params)
159        self.assertIn("RelayState", params)
160        self.assertIn("SigAlg", params)
161        self.assertIn("Signature", params)
162
163        # Verify signature algorithm matches provider configuration
164        self.assertEqual(params["SigAlg"][0], RSA_SHA256)
165
166        # Parse the SAMLRequest (unsigned XML)
167        parsed = self.parser.parse_detached(params["SAMLRequest"][0])
168        self.assertEqual(parsed.issuer, self.provider.issuer)
169
170    def test_form_data_can_be_parsed(self):
171        """Test that form data generates parseable POST request"""
172        # Get form data
173        form_data = self.processor.get_post_form_data()
174
175        # Parse the SAMLRequest from form data
176        parsed = self.parser.parse(form_data["SAMLRequest"])
177
178        # Verify parsing succeeded
179        self.assertEqual(parsed.issuer, self.provider.issuer)
180        self.assertEqual(parsed.name_id, "test@example.com")
181        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
182        self.assertEqual(parsed.session_index, "test-session-123")
183
184    def test_processor_without_optional_fields(self):
185        """Test integration when optional fields are missing"""
186        # Create processor without session_index and relay_state
187        processor = LogoutRequestProcessor(
188            provider=self.provider,
189            user=None,
190            destination="https://sp.example.com/sls",
191            name_id="minimal@example.com",
192            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
193            session_index=None,
194            relay_state=None,
195        )
196
197        # Test POST binding
198        encoded_post = processor.encode_post()
199        parsed_post = self.parser.parse(encoded_post)
200        self.assertEqual(parsed_post.name_id, "minimal@example.com")
201        self.assertIsNone(parsed_post.session_index)
202
203        # Test redirect binding
204        encoded_redirect = processor.encode_redirect()
205        parsed_redirect = self.parser.parse_detached(encoded_redirect)
206        self.assertEqual(parsed_redirect.name_id, "minimal@example.com")
207        self.assertIsNone(parsed_redirect.session_index)
208
209    def test_multiple_processors_same_provider(self):
210        """Test that multiple processors can use the same provider"""
211        # Create multiple processors with different data
212        processor1 = LogoutRequestProcessor(
213            provider=self.provider,
214            user=None,
215            destination="https://sp1.example.com/sls",
216            name_id="user1@example.com",
217            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
218            session_index="session-1",
219            relay_state="https://idp.example.com/flow1",
220        )
221
222        processor2 = LogoutRequestProcessor(
223            provider=self.provider,
224            user=None,
225            destination="https://sp2.example.com/sls",
226            name_id="user2@example.com",
227            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
228            session_index="session-2",
229            relay_state="https://idp.example.com/flow2",
230        )
231
232        # Generate requests
233        encoded1 = processor1.encode_post()
234        encoded2 = processor2.encode_post()
235
236        # Parse both with same parser
237        parsed1 = self.parser.parse(encoded1)
238        parsed2 = self.parser.parse(encoded2)
239
240        # Verify they have different data
241        self.assertEqual(parsed1.name_id, "user1@example.com")
242        self.assertEqual(parsed2.name_id, "user2@example.com")
243        self.assertEqual(parsed1.session_index, "session-1")
244        self.assertEqual(parsed2.session_index, "session-2")
245
246        # But same issuer
247        self.assertEqual(parsed1.issuer, parsed2.issuer)
248        self.assertEqual(parsed1.issuer, self.provider.issuer)

Integration tests for SAML Logout - processor and parser working together

def setUp(self):
21    def setUp(self):
22        """Set up test fixtures"""
23        self.flow = create_test_flow()
24        self.keypair = create_test_cert()
25
26        # Create provider
27        self.provider = SAMLProvider.objects.create(
28            name="test-provider",
29            authorization_flow=self.flow,
30            acs_url="https://sp.example.com/acs",
31            sls_url="https://sp.example.com/sls",
32            issuer="https://idp.example.com",
33            sp_binding="redirect",
34            sls_binding="redirect",
35            signature_algorithm=RSA_SHA256,
36        )
37
38        # Create processor
39        self.processor = LogoutRequestProcessor(
40            provider=self.provider,
41            user=None,
42            destination="https://sp.example.com/sls",
43            name_id="test@example.com",
44            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
45            session_index="test-session-123",
46            relay_state="https://idp.example.com/flow/return",
47        )
48
49        # Create parser for validation
50        self.parser = LogoutRequestParser(self.provider)

Set up test fixtures

def test_post_binding_roundtrip(self):
52    def test_post_binding_roundtrip(self):
53        """Test that a POST-encoded request can be parsed correctly"""
54        # Generate the request
55        encoded = self.processor.encode_post()
56
57        # Parse it back
58        parsed = self.parser.parse(encoded)
59
60        # Verify all fields match
61        self.assertEqual(parsed.issuer, self.provider.issuer)
62        self.assertEqual(parsed.name_id, "test@example.com")
63        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
64        self.assertEqual(parsed.session_index, "test-session-123")
65        self.assertIsNotNone(parsed.id)

Test that a POST-encoded request can be parsed correctly

def test_redirect_binding_roundtrip(self):
67    def test_redirect_binding_roundtrip(self):
68        """Test that a redirect-encoded request can be parsed correctly"""
69        # Generate the request
70        encoded = self.processor.encode_redirect()
71
72        # Parse it back using detached method
73        parsed = self.parser.parse_detached(encoded)
74
75        # Verify all fields match
76        self.assertEqual(parsed.issuer, self.provider.issuer)
77        self.assertEqual(parsed.name_id, "test@example.com")
78        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
79        self.assertEqual(parsed.session_index, "test-session-123")
80        self.assertIsNotNone(parsed.id)

Test that a redirect-encoded request can be parsed correctly

def test_signed_post_binding_roundtrip(self):
 82    def test_signed_post_binding_roundtrip(self):
 83        """Test that a signed POST request can be parsed and verified"""
 84        # Enable signing
 85        self.provider.signing_kp = self.keypair
 86        self.provider.sign_logout_request = True
 87        self.provider.save()
 88
 89        # Create new processor with signing
 90        processor = LogoutRequestProcessor(
 91            provider=self.provider,
 92            user=None,
 93            destination="https://sp.example.com/sls",
 94            name_id="signed@example.com",
 95            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
 96            session_index="signed-session-456",
 97            relay_state="https://idp.example.com/flow/signed",
 98        )
 99
100        # Generate signed request
101        encoded = processor.encode_post()
102
103        # Create parser with verification enabled
104        parser = LogoutRequestParser(self.provider)
105
106        # Parse it - this would validate signature if verification is enabled
107        parsed = parser.parse(encoded)
108
109        # Verify all fields match
110        self.assertEqual(parsed.issuer, self.provider.issuer)
111        self.assertEqual(parsed.name_id, "signed@example.com")
112        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
113        self.assertEqual(parsed.session_index, "signed-session-456")

Test that a signed POST request can be parsed and verified

def test_redirect_url_can_be_parsed(self):
115    def test_redirect_url_can_be_parsed(self):
116        """Test that the redirect URL contains parseable parameters"""
117        # Generate redirect URL
118        url = self.processor.get_redirect_url()
119
120        # Parse URL and extract SAMLRequest
121        parsed_url = urlparse(url)
122        params = parse_qs(parsed_url.query)
123
124        # Parse the SAMLRequest
125        saml_request = params["SAMLRequest"][0]
126        parsed = self.parser.parse_detached(saml_request)
127
128        # Verify parsing succeeded
129        self.assertEqual(parsed.issuer, self.provider.issuer)
130        self.assertEqual(parsed.name_id, "test@example.com")
131        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)

Test that the redirect URL contains parseable parameters

def test_signed_redirect_url_parameters(self):
133    def test_signed_redirect_url_parameters(self):
134        """Test that signed redirect URL has all required parameters for validation"""
135        # Enable signing
136        self.provider.signing_kp = self.keypair
137        self.provider.sign_logout_request = True
138        self.provider.save()
139
140        processor = LogoutRequestProcessor(
141            provider=self.provider,
142            user=None,
143            destination="https://sp.example.com/sls",
144            name_id="test@example.com",
145            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
146            session_index="test-session",
147            relay_state="https://idp.example.com/return",
148        )
149
150        # Generate signed redirect URL
151        url = processor.get_redirect_url()
152
153        # Parse URL
154        parsed_url = urlparse(url)
155        params = parse_qs(parsed_url.query)
156
157        # Verify all required parameters are present
158        self.assertIn("SAMLRequest", params)
159        self.assertIn("RelayState", params)
160        self.assertIn("SigAlg", params)
161        self.assertIn("Signature", params)
162
163        # Verify signature algorithm matches provider configuration
164        self.assertEqual(params["SigAlg"][0], RSA_SHA256)
165
166        # Parse the SAMLRequest (unsigned XML)
167        parsed = self.parser.parse_detached(params["SAMLRequest"][0])
168        self.assertEqual(parsed.issuer, self.provider.issuer)

Test that signed redirect URL has all required parameters for validation

def test_form_data_can_be_parsed(self):
170    def test_form_data_can_be_parsed(self):
171        """Test that form data generates parseable POST request"""
172        # Get form data
173        form_data = self.processor.get_post_form_data()
174
175        # Parse the SAMLRequest from form data
176        parsed = self.parser.parse(form_data["SAMLRequest"])
177
178        # Verify parsing succeeded
179        self.assertEqual(parsed.issuer, self.provider.issuer)
180        self.assertEqual(parsed.name_id, "test@example.com")
181        self.assertEqual(parsed.name_id_format, SAML_NAME_ID_FORMAT_EMAIL)
182        self.assertEqual(parsed.session_index, "test-session-123")

Test that form data generates parseable POST request

def test_processor_without_optional_fields(self):
184    def test_processor_without_optional_fields(self):
185        """Test integration when optional fields are missing"""
186        # Create processor without session_index and relay_state
187        processor = LogoutRequestProcessor(
188            provider=self.provider,
189            user=None,
190            destination="https://sp.example.com/sls",
191            name_id="minimal@example.com",
192            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
193            session_index=None,
194            relay_state=None,
195        )
196
197        # Test POST binding
198        encoded_post = processor.encode_post()
199        parsed_post = self.parser.parse(encoded_post)
200        self.assertEqual(parsed_post.name_id, "minimal@example.com")
201        self.assertIsNone(parsed_post.session_index)
202
203        # Test redirect binding
204        encoded_redirect = processor.encode_redirect()
205        parsed_redirect = self.parser.parse_detached(encoded_redirect)
206        self.assertEqual(parsed_redirect.name_id, "minimal@example.com")
207        self.assertIsNone(parsed_redirect.session_index)

Test integration when optional fields are missing

def test_multiple_processors_same_provider(self):
209    def test_multiple_processors_same_provider(self):
210        """Test that multiple processors can use the same provider"""
211        # Create multiple processors with different data
212        processor1 = LogoutRequestProcessor(
213            provider=self.provider,
214            user=None,
215            destination="https://sp1.example.com/sls",
216            name_id="user1@example.com",
217            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
218            session_index="session-1",
219            relay_state="https://idp.example.com/flow1",
220        )
221
222        processor2 = LogoutRequestProcessor(
223            provider=self.provider,
224            user=None,
225            destination="https://sp2.example.com/sls",
226            name_id="user2@example.com",
227            name_id_format=SAML_NAME_ID_FORMAT_EMAIL,
228            session_index="session-2",
229            relay_state="https://idp.example.com/flow2",
230        )
231
232        # Generate requests
233        encoded1 = processor1.encode_post()
234        encoded2 = processor2.encode_post()
235
236        # Parse both with same parser
237        parsed1 = self.parser.parse(encoded1)
238        parsed2 = self.parser.parse(encoded2)
239
240        # Verify they have different data
241        self.assertEqual(parsed1.name_id, "user1@example.com")
242        self.assertEqual(parsed2.name_id, "user2@example.com")
243        self.assertEqual(parsed1.session_index, "session-1")
244        self.assertEqual(parsed2.session_index, "session-2")
245
246        # But same issuer
247        self.assertEqual(parsed1.issuer, parsed2.issuer)
248        self.assertEqual(parsed1.issuer, self.provider.issuer)

Test that multiple processors can use the same provider