• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grafana / django-saml2-auth / 10105870444

26 Jul 2024 04:47AM UTC coverage: 90.335%. Remained the same
10105870444

Pull #335

github

web-flow
Merge 40208893c into d8af16360
Pull Request #335: Bump pytest from 8.1.1 to 8.3.2

916 of 1014 relevant lines covered (90.34%)

6.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/django_saml2_auth/tests/test_saml.py
1
"""
7✔
2
Tests for saml.py
3
"""
4

5
from typing import Dict, Optional, List, Mapping, Union
7✔
6

7
import pytest
7✔
8
import responses
7✔
9
from django.contrib.sessions.middleware import SessionMiddleware
7✔
10
from unittest.mock import MagicMock
7✔
11
from django.http import HttpRequest
7✔
12
from django.test.client import RequestFactory
7✔
13
from django.urls import NoReverseMatch
7✔
14
from django_saml2_auth.exceptions import SAMLAuthError
7✔
15
from django_saml2_auth.saml import (
7✔
16
    decode_saml_response,
17
    extract_user_identity,
18
    get_assertion_url,
19
    get_default_next_url,
20
    get_metadata,
21
    get_saml_client,
22
    validate_metadata_url,
23
)
24
from django_saml2_auth.views import acs
7✔
25
from pytest_django.fixtures import SettingsWrapper
7✔
26
from saml2.client import Saml2Client
7✔
27
from saml2.response import AuthnResponse
7✔
28
from django_saml2_auth import user
7✔
29

30

31
GET_METADATA_AUTO_CONF_URLS = (
7✔
32
    "django_saml2_auth.tests.test_saml.get_metadata_auto_conf_urls"
33
)
34
METADATA_URL1 = "https://testserver1.com/saml/sso/metadata"
7✔
35
METADATA_URL2 = "https://testserver2.com/saml/sso/metadata"
7✔
36
# Ref: https://en.wikipedia.org/wiki/SAML_metadata#Entity_metadata
37
METADATA1 = b"""
7✔
38
<md:EntityDescriptor entityID="https://testserver1.com/entity" validUntil="2025-08-30T19:10:29Z"
39
    xmlns:md="urn:oasis:names:tc:SAML:2.0:METADATA1"
40
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
41
    xmlns:mdrpi="urn:oasis:names:tc:SAML:METADATA1:rpi"
42
    xmlns:mdattr="urn:oasis:names:tc:SAML:METADATA1:attribute"
43
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
44
    <!-- insert ds:Signature element (omitted) -->
45
    <md:Extensions>
46
    <mdrpi:RegistrationInfo registrationAuthority="https://testserver1.com/"/>
47
    <mdrpi:PublicationInfo creationInstant="2025-08-16T19:10:29Z" publisher="https://testserver1.com/"/>
48
    <mdattr:EntityAttributes>
49
        <saml:Attribute Name="https://testserver1.com/entity-category" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
50
        <saml:AttributeValue>https://testserver1.com/category/self-certified</saml:AttributeValue>
51
        </saml:Attribute>
52
    </mdattr:EntityAttributes>
53
    </md:Extensions>
54
    <!-- insert one or more concrete instances of the md:RoleDescriptor abstract type (see below) -->
55
    <md:Organization>
56
    <md:OrganizationName xml:lang="en">...</md:OrganizationName>
57
    <md:OrganizationDisplayName xml:lang="en">...</md:OrganizationDisplayName>
58
    <md:OrganizationURL xml:lang="en">https://testserver1.com/</md:OrganizationURL>
59
    </md:Organization>
60
    <md:ContactPerson contactType="technical">
61
    <md:SurName>SAML Technical Support</md:SurName>
62
    <md:EmailAddress>mailto:technical-support@example.info</md:EmailAddress>
63
    </md:ContactPerson>
64
</md:EntityDescriptor>"""
65
METADATA2 = b"""
7✔
66
<md:EntityDescriptor entityID="https://testserver2.com/entity" validUntil="2025-08-30T19:10:29Z"
67
    xmlns:md="urn:oasis:names:tc:SAML:2.0:METADATA1"
68
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
69
    xmlns:mdrpi="urn:oasis:names:tc:SAML:METADATA1:rpi"
70
    xmlns:mdattr="urn:oasis:names:tc:SAML:METADATA1:attribute"
71
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
72
    <!-- insert ds:Signature element (omitted) -->
73
    <md:Extensions>
74
    <mdrpi:RegistrationInfo registrationAuthority="https://testserver2.com/"/>
75
    <mdrpi:PublicationInfo creationInstant="2025-08-16T19:10:29Z" publisher="https://testserver2.com/"/>
76
    <mdattr:EntityAttributes>
77
        <saml:Attribute Name="https://testserver2.com/entity-category" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
78
        <saml:AttributeValue>https://testserver2.com/category/self-certified</saml:AttributeValue>
79
        </saml:Attribute>
80
    </mdattr:EntityAttributes>
81
    </md:Extensions>
82
    <!-- insert one or more concrete instances of the md:RoleDescriptor abstract type (see below) -->
83
    <md:Organization>
84
    <md:OrganizationName xml:lang="en">...</md:OrganizationName>
85
    <md:OrganizationDisplayName xml:lang="en">...</md:OrganizationDisplayName>
86
    <md:OrganizationURL xml:lang="en">https://testserver2.com/</md:OrganizationURL>
87
    </md:Organization>
88
    <md:ContactPerson contactType="technical">
89
    <md:SurName>SAML Technical Support</md:SurName>
90
    <md:EmailAddress>mailto:technical-support@example.info</md:EmailAddress>
91
    </md:ContactPerson>
92
</md:EntityDescriptor>"""
93

94

95
def get_metadata_auto_conf_urls(
7✔
96
    user_id: Optional[str] = None,
97
) -> List[Optional[Mapping[str, str]]]:
98
    """Fixture for returning metadata autoconf URL(s) based on the user_id.
99

100
    Args:
101
        user_id (str, optional): User identifier: username or email. Defaults to None.
102

103
    Returns:
104
        list: Either an empty list or a list of valid metadata URL(s)
105
    """
106
    if user_id == "nonexistent_user@example.com":
7✔
107
        return []
7✔
108
    if user_id == "test@example.com":
7✔
109
        return [{"url": METADATA_URL1}]
7✔
110
    return [{"url": METADATA_URL1}, {"url": METADATA_URL2}]
7✔
111

112

113
def get_user_identity() -> Mapping[str, List[str]]:
7✔
114
    """Fixture for returning user identity produced by pysaml2.
115

116
    Returns:
117
        dict: keys are SAML attributes and values are lists of attribute values
118
    """
119
    return {
7✔
120
        "user.username": ["test@example.com"],
121
        "user.email": ["test@example.com"],
122
        "user.first_name": ["John"],
123
        "user.last_name": ["Doe"],
124
        "token": ["TOKEN"],
125
    }
126

127

128
def mock_parse_authn_request_response(
7✔
129
    self: Saml2Client, response: AuthnResponse, binding: str
130
) -> "MockAuthnResponse":  # type: ignore # noqa: F821
131
    """Mock function to return an mocked instance of AuthnResponse.
132

133
    Returns:
134
        MockAuthnResponse: A mocked instance of AuthnResponse
135
    """
136

137
    class MockAuthnRequest:
7✔
138
        """Mock class for AuthnRequest."""
7✔
139

140
        name_id = "Username"
7✔
141

142
        @staticmethod
7✔
143
        def issuer():
7✔
144
            """Mock function for AuthnRequest.issuer()."""
145
            return METADATA_URL1
7✔
146

147
        @staticmethod
7✔
148
        def get_identity():
7✔
149
            """Mock function for AuthnRequest.get_identity()."""
150
            return get_user_identity()
7✔
151

152
    return MockAuthnRequest()
7✔
153

154

155
def test_get_assertion_url_success():
7✔
156
    """Test get_assertion_url function to verify if it correctly returns the default assertion URL."""
157
    assertion_url = get_assertion_url(HttpRequest())
7✔
158
    assert assertion_url == "https://api.example.com"
7✔
159

160

161
def test_get_assertion_url_no_assertion_url(settings: SettingsWrapper):
7✔
162
    """Test get_assertion_url function to verify if it correctly returns the server's assertion URL
163
    based on the incoming request.
164

165
    Args:
166
        settings (SettingsWrapper): Fixture for django settings
167
    """
168
    settings.SAML2_AUTH["ASSERTION_URL"] = None
7✔
169
    get_request = RequestFactory().get("/acs/")
7✔
170
    assertion_url = get_assertion_url(get_request)
7✔
171
    assert assertion_url == "http://testserver"
7✔
172

173

174
def test_get_default_next_url_success():
7✔
175
    """Test get_default_next_url to verify if it returns the correct default next URL."""
176
    default_next_url = get_default_next_url()
7✔
177
    assert default_next_url == "http://app.example.com/account/login"
7✔
178

179

180
def test_get_default_next_url_no_default_next_url(settings: SettingsWrapper):
7✔
181
    """Test get_default_next_url function with no default next url for redirection to see if it
182
    returns the admin:index route.
183

184
    Args:
185
        settings (SettingsWrapper): Fixture for django settings
186
    """
187
    settings.SAML2_AUTH["DEFAULT_NEXT_URL"] = None
7✔
188
    with pytest.raises(SAMLAuthError) as exc_info:
7✔
189
        get_default_next_url()
7✔
190

191
    # This doesn't happen on a real instance, unless you don't have "admin:index" route
192
    assert str(exc_info.value) == "We got a URL reverse issue: ['admin:index']"
7✔
193
    assert exc_info.value.extra is not None
7✔
194
    assert issubclass(exc_info.value.extra["exc_type"], NoReverseMatch)
7✔
195

196

197
@responses.activate
7✔
198
def test_validate_metadata_url_success():
7✔
199
    """Test validate_metadata_url function to verify a valid metadata URL."""
200
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
201
    result = validate_metadata_url(METADATA_URL1)
7✔
202
    assert result
7✔
203

204

205
@responses.activate
7✔
206
def test_validate_metadata_url_failure():
7✔
207
    """Test validate_metadata_url function to verify if it correctly identifies an invalid metadata
208
    URL."""
209
    responses.add(responses.GET, METADATA_URL1)
7✔
210
    result = validate_metadata_url(METADATA_URL1)
7✔
211
    assert result is False
7✔
212

213

214
@responses.activate
7✔
215
def test_get_metadata_success_with_single_metadata_url(settings: SettingsWrapper):
7✔
216
    """Test get_metadata function to verify if it returns a valid metadata URL with a correct
217
    format.
218

219
    Args:
220
        settings (SettingsWrapper): Fixture for django settings
221
    """
222
    settings.SAML2_AUTH["METADATA_AUTO_CONF_URL"] = METADATA_URL1
7✔
223
    settings.SAML2_AUTH["TRIGGER"]["GET_METADATA_AUTO_CONF_URLS"] = None
7✔
224
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
225

226
    result = get_metadata()
7✔
227
    assert result == {"remote": [{"url": METADATA_URL1}]}
7✔
228

229

230
def test_get_metadata_failure_with_invalid_metadata_url(settings: SettingsWrapper):
7✔
231
    """Test get_metadata function to verify if it fails with invalid metadata information.
232

233
    Args:
234
        settings (SettingsWrapper): Fixture for django settings
235
    """
236
    # HTTP Responses are not mocked, so this will fail.
237
    settings.SAML2_AUTH["METADATA_AUTO_CONF_URL"] = METADATA_URL1
7✔
238
    settings.SAML2_AUTH["TRIGGER"]["GET_METADATA_AUTO_CONF_URLS"] = None
7✔
239

240
    with pytest.raises(SAMLAuthError) as exc_info:
7✔
241
        get_metadata()
7✔
242

243
    assert str(exc_info.value) == "Invalid metadata URL."
7✔
244

245

246
@responses.activate
7✔
247
def test_get_metadata_success_with_multiple_metadata_urls(settings: SettingsWrapper):
7✔
248
    """Test get_metadata function to verify if it returns multiple metadata URLs if the user_id is
249
    unknown.
250

251
    Args:
252
        settings (SettingsWrapper): Fixture for django settings
253
    """
254
    settings.SAML2_AUTH["TRIGGER"][
7✔
255
        "GET_METADATA_AUTO_CONF_URLS"
256
    ] = GET_METADATA_AUTO_CONF_URLS
257
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
258
    responses.add(responses.GET, METADATA_URL2, body=METADATA2)
7✔
259

260
    result = get_metadata()
7✔
261
    assert result == {"remote": [{"url": METADATA_URL1}, {"url": METADATA_URL2}]}
7✔
262

263

264
@responses.activate
7✔
265
def test_get_metadata_success_with_user_id(settings: SettingsWrapper):
7✔
266
    """Test get_metadata function to verify if it returns a valid metadata URLs given the user_id.
267

268
    Args:
269
        settings (SettingsWrapper): Fixture for django settings
270
    """
271
    settings.SAML2_AUTH["TRIGGER"][
7✔
272
        "GET_METADATA_AUTO_CONF_URLS"
273
    ] = GET_METADATA_AUTO_CONF_URLS
274
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
275

276
    result = get_metadata("test@example.com")
7✔
277
    assert result == {"remote": [{"url": METADATA_URL1}]}
7✔
278

279

280
def test_get_metadata_failure_with_nonexistent_user_id(settings: SettingsWrapper):
7✔
281
    """Test get_metadata function to verify if it raises an exception given a nonexistent user_id.
282

283
    Args:
284
        settings (SettingsWrapper): Fixture for django settings
285
    """
286
    settings.SAML2_AUTH["TRIGGER"][
7✔
287
        "GET_METADATA_AUTO_CONF_URLS"
288
    ] = GET_METADATA_AUTO_CONF_URLS
289

290
    with pytest.raises(SAMLAuthError) as exc_info:
7✔
291
        get_metadata("nonexistent_user@example.com")
7✔
292
    assert (
7✔
293
        str(exc_info.value)
294
        == "No metadata URL associated with the given user identifier."
295
    )
296

297

298
def test_get_metadata_success_with_local_file(settings: SettingsWrapper):
7✔
299
    """Test get_metadata function to verify if correctly returns path to local metadata file.
300

301
    Args:
302
        settings (SettingsWrapper): Fixture for django settings
303
    """
304
    settings.SAML2_AUTH["TRIGGER"]["GET_METADATA_AUTO_CONF_URLS"] = None
7✔
305
    settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = "/absolute/path/to/metadata.xml"
7✔
306

307
    result = get_metadata()
7✔
308
    assert result == {"local": ["/absolute/path/to/metadata.xml"]}
7✔
309

310

311
def test_get_saml_client_success(settings: SettingsWrapper):
7✔
312
    """Test get_saml_client function to verify if it is correctly instantiated with local metadata
313
    file.
314

315
    Args:
316
        settings (SettingsWrapper): Fixture for django settings
317
    """
318
    settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = (
7✔
319
        "django_saml2_auth/tests/metadata.xml"
320
    )
321
    result = get_saml_client("example.com", acs)
7✔
322
    assert isinstance(result, Saml2Client)
7✔
323

324

325
@responses.activate
7✔
326
def test_get_saml_client_success_with_user_id(settings: SettingsWrapper):
7✔
327
    """Test get_saml_client function to verify if it is correctly instantiated with remote metadata
328
    URL and valid user_id.
329

330
    Args:
331
        settings (SettingsWrapper): Fixture for django settings
332
    """
333
    settings.SAML2_AUTH["TRIGGER"][
7✔
334
        "GET_METADATA_AUTO_CONF_URLS"
335
    ] = GET_METADATA_AUTO_CONF_URLS
336
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
337

338
    result = get_saml_client("example.com", acs, "test@example.com")
7✔
339
    assert isinstance(result, Saml2Client)
7✔
340

341

342
def test_get_saml_client_failure_with_missing_metadata_url(settings: SettingsWrapper):
7✔
343
    """Test get_saml_client function to verify if it raises an exception given a missing non-mocked
344
    metadata URL.
345

346
    Args:
347
        settings (SettingsWrapper): Fixture for django settings
348
    """
349
    settings.SAML2_AUTH["TRIGGER"][
7✔
350
        "GET_METADATA_AUTO_CONF_URLS"
351
    ] = GET_METADATA_AUTO_CONF_URLS
352

353
    with pytest.raises(SAMLAuthError) as exc_info:
7✔
354
        get_saml_client("example.com", acs, "test@example.com")
7✔
355

356
    assert str(exc_info.value) == "Metadata URL/file is missing."
7✔
357

358

359
def test_get_saml_client_failure_with_invalid_file(settings: SettingsWrapper):
7✔
360
    """Test get_saml_client function to verify if it raises an exception given an invalid path to
361
    metadata file.
362

363
    Args:
364
        settings (SettingsWrapper): Fixture for django settings
365
    """
366
    settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = "/invalid/metadata.xml"
7✔
367
    settings.SAML2_AUTH["TRIGGER"]["GET_METADATA_AUTO_CONF_URLS"] = None
7✔
368

369
    with pytest.raises(SAMLAuthError) as exc_info:
7✔
370
        get_saml_client("example.com", acs)
7✔
371

372
    assert (
7✔
373
        str(exc_info.value)
374
        == "[Errno 2] No such file or directory: '/invalid/metadata.xml'"
375
    )
376
    assert exc_info.value.extra is not None
7✔
377
    assert isinstance(exc_info.value.extra["exc"], FileNotFoundError)
7✔
378

379

380
@pytest.mark.parametrize(
7✔
381
    "supplied_config_values,expected_encryption_keypairs",
382
    [
383
        (
384
            {
385
                "KEY_FILE": "django_saml2_auth/tests/dummy_key.pem",
386
            },
387
            None,
388
        ),
389
        (
390
            {
391
                "CERT_FILE": "django_saml2_auth/tests/dummy_cert.pem",
392
            },
393
            None,
394
        ),
395
        (
396
            {
397
                "KEY_FILE": "django_saml2_auth/tests/dummy_key.pem",
398
                "CERT_FILE": "django_saml2_auth/tests/dummy_cert.pem",
399
            },
400
            [
401
                {
402
                    "key_file": "django_saml2_auth/tests/dummy_key.pem",
403
                    "cert_file": "django_saml2_auth/tests/dummy_cert.pem",
404
                }
405
            ],
406
        ),
407
    ],
408
)
409
def test_get_saml_client_success_with_key_and_cert_files(
7✔
410
    settings: SettingsWrapper,
411
    supplied_config_values: Dict[str, str],
412
    expected_encryption_keypairs: Union[List, None],
413
):
414
    """Test get_saml_client function to verify that it is correctly instantiated with encryption_keypairs
415
    if both key_file and cert_file are provided (even if encryption_keypairs isn't).
416

417
    Args:
418
        settings (SettingsWrapper): Fixture for django settings
419
    """
420

421
    settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = (
7✔
422
        "django_saml2_auth/tests/metadata.xml"
423
    )
424

425
    for key, value in supplied_config_values.items():
7✔
426
        settings.SAML2_AUTH[key] = value
7✔
427

428
    result = get_saml_client("example.com", acs)
7✔
429
    assert isinstance(result, Saml2Client)
7✔
430
    assert result.config.encryption_keypairs == expected_encryption_keypairs
7✔
431

432
    for key, value in supplied_config_values.items():
7✔
433
        # ensure that the added settings do not get carried over to other tests
434
        del settings.SAML2_AUTH[key]
7✔
435

436

437
@responses.activate
7✔
438
def test_decode_saml_response_success(
7✔
439
    settings: SettingsWrapper,
440
    monkeypatch: "MonkeyPatch",  # type: ignore # noqa: F821
441
):
442
    """Test decode_saml_response function to verify if it correctly decodes the SAML response.
443

444
    Args:
445
        settings (SettingsWrapper): Fixture for django settings
446
        monkeypatch (MonkeyPatch): PyTest monkeypatch fixture
447
    """
448
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
449
    settings.SAML2_AUTH["ASSERTION_URL"] = "https://api.example.com"
7✔
450
    settings.SAML2_AUTH["TRIGGER"][
7✔
451
        "GET_METADATA_AUTO_CONF_URLS"
452
    ] = GET_METADATA_AUTO_CONF_URLS
453

454
    post_request = RequestFactory().post(
7✔
455
        METADATA_URL1, {"SAMLResponse": "SAML RESPONSE"}
456
    )
457
    monkeypatch.setattr(
7✔
458
        Saml2Client, "parse_authn_request_response", mock_parse_authn_request_response
459
    )
460
    result = decode_saml_response(post_request, acs)
7✔
461
    assert len(result.get_identity()) > 0  # type: ignore
7✔
462

463

464
def test_extract_user_identity_success():
7✔
465
    """Test extract_user_identity function to verify if it correctly extracts user identity
466
    information from a (pysaml2) parsed SAML response."""
467
    result = extract_user_identity(get_user_identity())  # type: ignore
7✔
468
    assert len(result) == 6
7✔
469
    assert result["username"] == result["email"] == "test@example.com"
7✔
470
    assert result["first_name"] == "John"
7✔
471
    assert result["last_name"] == "Doe"
7✔
472
    assert result["token"] == "TOKEN"
7✔
473
    assert result["user_identity"] == get_user_identity()
7✔
474

475

476
def test_extract_user_identity_token_not_required(settings: SettingsWrapper):
7✔
477
    """Test extract_user_identity function to verify if it correctly extracts user identity
478
    information from a (pysaml2) parsed SAML response when token is not required."""
479
    settings.SAML2_AUTH["TOKEN_REQUIRED"] = False
7✔
480

481
    result = extract_user_identity(get_user_identity())  # type: ignore
7✔
482
    assert len(result) == 5
7✔
483
    assert "token" not in result
7✔
484

485

486
@pytest.mark.django_db
7✔
487
@responses.activate
7✔
488
def test_acs_view_when_next_url_is_none(
7✔
489
    settings: SettingsWrapper,
490
    monkeypatch: "MonkeyPatch",  # type: ignore # noqa: F821
491
):
492
    """Test Acs view when login_next_url is None in the session"""
493
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
494
    settings.SAML2_AUTH = {
7✔
495
        "ASSERTION_URL": "https://api.example.com",
496
        "DEFAULT_NEXT_URL": "default_next_url",
497
        "USE_JWT": False,
498
        "TRIGGER": {
499
            "BEFORE_LOGIN": None,
500
            "AFTER_LOGIN": None,
501
            "GET_METADATA_AUTO_CONF_URLS": GET_METADATA_AUTO_CONF_URLS,
502
        },
503
    }
504
    post_request = RequestFactory().post(
7✔
505
        METADATA_URL1, {"SAMLResponse": "SAML RESPONSE"}
506
    )
507

508
    monkeypatch.setattr(
7✔
509
        Saml2Client, "parse_authn_request_response", mock_parse_authn_request_response
510
    )
511

512
    created, mock_user = user.get_or_create_user(
7✔
513
        {"username": "test@example.com", "first_name": "John", "last_name": "Doe"}
514
    )
515

516
    monkeypatch.setattr(
7✔
517
        user,
518
        "get_or_create_user",
519
        (
520
            created,
521
            mock_user,
522
        ),
523
    )
524

525
    middleware = SessionMiddleware(MagicMock())
7✔
526
    middleware.process_request(post_request)
7✔
527
    post_request.session["login_next_url"] = None
7✔
528
    post_request.session.save()
7✔
529

530
    result = acs(post_request)
7✔
531
    assert result["Location"] == "default_next_url"
7✔
532

533

534
@pytest.mark.django_db
7✔
535
@responses.activate
7✔
536
def test_acs_view_when_redirection_state_is_passed_in_relay_state(
7✔
537
    settings: SettingsWrapper,
538
    monkeypatch: "MonkeyPatch",  # type: ignore # noqa: F821
539
):
540
    """Test Acs view when login_next_url is None and redirection state in POST request"""
541
    responses.add(responses.GET, METADATA_URL1, body=METADATA1)
7✔
542
    settings.SAML2_AUTH = {
7✔
543
        "ASSERTION_URL": "https://api.example.com",
544
        "DEFAULT_NEXT_URL": "default_next_url",
545
        "USE_JWT": False,
546
        "TRIGGER": {
547
            "BEFORE_LOGIN": None,
548
            "AFTER_LOGIN": None,
549
            "GET_METADATA_AUTO_CONF_URLS": GET_METADATA_AUTO_CONF_URLS,
550
        },
551
    }
552
    post_request = RequestFactory().post(
7✔
553
        METADATA_URL1, {"SAMLResponse": "SAML RESPONSE", "RelayState": "/admin/logs"}
554
    )
555

556
    monkeypatch.setattr(
7✔
557
        Saml2Client, "parse_authn_request_response", mock_parse_authn_request_response
558
    )
559

560
    created, mock_user = user.get_or_create_user(
7✔
561
        {"username": "test@example.com", "first_name": "John", "last_name": "Doe"}
562
    )
563

564
    monkeypatch.setattr(
7✔
565
        user,
566
        "get_or_create_user",
567
        (
568
            created,
569
            mock_user,
570
        ),
571
    )
572

573
    middleware = SessionMiddleware(MagicMock())
7✔
574
    middleware.process_request(post_request)
7✔
575
    post_request.session["login_next_url"] = None
7✔
576
    post_request.session.save()
7✔
577

578
    result = acs(post_request)
7✔
579
    assert result["Location"] == "/admin/logs"
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc