Skip to content

Commit

Permalink
Move use_jwt block below login block
Browse files Browse the repository at this point in the history
  • Loading branch information
HybridAU committed Feb 25, 2025
1 parent 801bdb2 commit dc02454
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 18 deletions.
79 changes: 79 additions & 0 deletions django_saml2_auth/tests/test_saml.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.urls import NoReverseMatch
from saml2 import BINDING_HTTP_POST

from django_saml2_auth.errors import INACTIVE_USER
from django_saml2_auth.exceptions import SAMLAuthError
from django_saml2_auth.saml import (
decode_saml_response,
Expand Down Expand Up @@ -771,3 +772,81 @@ def test_get_metadata_success_with_custom_trigger(settings: SettingsWrapper):
get_metadata(domain="not-mapped-example.com")

assert str(exc_info.value) == "Domain not-mapped-example.com not mapped!"


@pytest.mark.django_db
@responses.activate
def test_acs_view_when_use_jwt_set_redirects_user(
settings: SettingsWrapper,
monkeypatch: "MonkeyPatch", # type: ignore # noqa: F821
):
"""Test Acs view when USE_JWT is set that the user is correctly redirected"""
responses.add(responses.GET, METADATA_URL1, body=METADATA1)
settings.SAML2_AUTH = {
"DEFAULT_NEXT_URL": "default_next_url",
"USE_JWT": True,
"JWT_SECRET": "JWT_SECRET",
"JWT_ALGORITHM": "HS256",
"FRONTEND_URL": "https://app.example.com/account/login/saml",
"TRIGGER": {
"BEFORE_LOGIN": None,
"AFTER_LOGIN": None,
"GET_METADATA_AUTO_CONF_URLS": GET_METADATA_AUTO_CONF_URLS,
},
}
post_request = RequestFactory().post(METADATA_URL1, {"SAMLResponse": "SAML RESPONSE"})
monkeypatch.setattr(
Saml2Client, "parse_authn_request_response", mock_parse_authn_request_response
)
created, mock_user = user.get_or_create_user(
{"username": "[email protected]", "first_name": "John", "last_name": "Doe"}
)
monkeypatch.setattr(user, "get_or_create_user", (created, mock_user))

middleware = SessionMiddleware(MagicMock())
middleware.process_request(post_request)
post_request.session.save()

result = acs(post_request)
assert result.status_code == 302
assert "https://app.example.com/account/login/saml?token=eyJ" in result.url


@pytest.mark.django_db
@responses.activate
def test_acs_view_use_jwt_set_inactive_user(
settings: SettingsWrapper,
monkeypatch: "MonkeyPatch", # type: ignore # noqa: F821
):
"""Test Acs view when USE_JWT is set that inactive users can not log in"""
responses.add(responses.GET, METADATA_URL1, body=METADATA1)
settings.SAML2_AUTH = {
"DEFAULT_NEXT_URL": "default_next_url",
"USE_JWT": True,
"JWT_SECRET": "JWT_SECRET",
"JWT_ALGORITHM": "HS256",
"FRONTEND_URL": "https://app.example.com/account/login/saml",
"TRIGGER": {
"BEFORE_LOGIN": None,
"AFTER_LOGIN": None,
"GET_METADATA_AUTO_CONF_URLS": GET_METADATA_AUTO_CONF_URLS,
},
}
post_request = RequestFactory().post(METADATA_URL1, {"SAMLResponse": "SAML RESPONSE"})
monkeypatch.setattr(
Saml2Client, "parse_authn_request_response", mock_parse_authn_request_response
)
created, mock_user = user.get_or_create_user(
{"username": "[email protected]", "first_name": "John", "last_name": "Doe"}
)
mock_user.is_active = False
mock_user.save()
monkeypatch.setattr(user, "get_or_create_user", (created, mock_user))

middleware = SessionMiddleware(MagicMock())
middleware.process_request(post_request)
post_request.session.save()

result = acs(post_request)
assert result.status_code == 500
assert f"Error code: {INACTIVE_USER}" in result.content.decode()
37 changes: 19 additions & 18 deletions django_saml2_auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,24 +149,6 @@ def acs(request: HttpRequest):

request.session.flush()

use_jwt = dictor(saml2_auth_settings, "USE_JWT", False)
if use_jwt and target_user.is_active:
# Create a new JWT token for IdP-initiated login (acs)
jwt_token = create_custom_or_default_jwt(target_user)
custom_token_query_trigger = dictor(saml2_auth_settings, "TRIGGER.CUSTOM_TOKEN_QUERY")
if custom_token_query_trigger:
query = run_hook(custom_token_query_trigger, jwt_token)
else:
query = f"?token={jwt_token}"

# Use JWT auth to send token to frontend
frontend_url = dictor(saml2_auth_settings, "FRONTEND_URL", next_url)
custom_frontend_url_trigger = dictor(saml2_auth_settings, "TRIGGER.GET_CUSTOM_FRONTEND_URL")
if custom_frontend_url_trigger:
frontend_url = run_hook(custom_frontend_url_trigger, relay_state) # type: ignore

return HttpResponseRedirect(frontend_url + query)

if target_user.is_active:
# Try to load from the `AUTHENTICATION_BACKENDS` setting in settings.py
if hasattr(settings, "AUTHENTICATION_BACKENDS") and settings.AUTHENTICATION_BACKENDS:
Expand All @@ -190,6 +172,25 @@ def acs(request: HttpRequest):
},
)

use_jwt = dictor(saml2_auth_settings, "USE_JWT", False)
if use_jwt:
# Create a new JWT token for IdP-initiated login (acs)
jwt_token = create_custom_or_default_jwt(target_user)
custom_token_query_trigger = dictor(saml2_auth_settings, "TRIGGER.CUSTOM_TOKEN_QUERY")
if custom_token_query_trigger:
query = run_hook(custom_token_query_trigger, jwt_token)
else:
query = f"?token={jwt_token}"

# Use JWT auth to send token to frontend
frontend_url = dictor(saml2_auth_settings, "FRONTEND_URL", next_url)
custom_frontend_url_trigger = dictor(saml2_auth_settings, "TRIGGER.GET_CUSTOM_FRONTEND_URL")
if custom_frontend_url_trigger:
frontend_url = run_hook(custom_frontend_url_trigger, relay_state) # type: ignore

return HttpResponseRedirect(frontend_url + query)


def redirect(redirect_url: Optional[str] = None) -> HttpResponseRedirect:
"""Redirect to the redirect_url or the root page.
Expand Down

0 comments on commit dc02454

Please sign in to comment.