Skip to content

Commit dc1598c

Browse files
authored
Allow claims-like attribute keys (#253)
* added feature and tests * added author * cleanup * cleanup and add .idea (intellij) to .gitignore * remove nested .idea/ * cleanup debugging * Remove unused file * Reformat with ruff
1 parent b272b06 commit dc1598c

File tree

4 files changed

+45
-5
lines changed

4 files changed

+45
-5
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ target/
6363

6464
# IDEs
6565
.vscode/
66+
.idea/

AUTHORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ an issue.
5959
- [Santiago Gandolfo](https://github.com/santigandolfo)
6060
- [Greg Wong](https://github.com/gregorywong)
6161
- [Michael V. Battista](https://github.com/mvbattista)
62+
- [William Abbott](https://github.com/wrabit)

django_saml2_auth/saml.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -402,15 +402,15 @@ def extract_user_identity(user_identity: Dict[str, Any]) -> Dict[str, Optional[A
402402
)
403403

404404
user = {}
405-
user["email"] = dictor(user_identity, f"{email_field}/0", pathsep="/") # Path includes "."
406-
user["username"] = dictor(user_identity, f"{username_field}/0", pathsep="/")
407-
user["first_name"] = dictor(user_identity, f"{firstname_field}/0", pathsep="/")
408-
user["last_name"] = dictor(user_identity, f"{lastname_field}/0", pathsep="/")
405+
user["email"] = dictor(user_identity, f"{email_field}|0", pathsep="|") # Path includes "."
406+
user["username"] = dictor(user_identity, f"{username_field}|0", pathsep="|")
407+
user["first_name"] = dictor(user_identity, f"{firstname_field}|0", pathsep="|")
408+
user["last_name"] = dictor(user_identity, f"{lastname_field}|0", pathsep="|")
409409

410410
token_required = dictor(saml2_auth_settings, "TOKEN_REQUIRED", default=True)
411411
if token_required:
412412
token_field = dictor(saml2_auth_settings, "ATTRIBUTES_MAP.token", default="token")
413-
user["token"] = dictor(user_identity, f"{token_field}.0")
413+
user["token"] = dictor(user_identity, f"{token_field}|0", pathsep="|")
414414

415415
if user["email"]:
416416
user["email"] = user["email"].lower()

django_saml2_auth/tests/test_saml.py

+38
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,21 @@ def get_user_identity() -> Mapping[str, List[str]]:
123123
}
124124

125125

126+
def get_user_identify_with_slashed_keys() -> Mapping[str, List[str]]:
127+
"""Fixture for returning user identity produced by pysaml2 with slashed, claim-like keys.
128+
129+
Returns:
130+
dict: keys are SAML attributes and values are lists of attribute values
131+
"""
132+
return {
133+
"http://schemas.org/user/username": ["[email protected]"],
134+
"http://schemas.org/user/claim2.0/email": ["[email protected]"],
135+
"http://schemas.org/user/claim2.0/first_name": ["John"],
136+
"http://schemas.org/user/claim2.0/last_name": ["Doe"],
137+
"http://schemas.org/auth/server/token": ["TOKEN"],
138+
}
139+
140+
126141
def mock_parse_authn_request_response(
127142
self: Saml2Client, response: AuthnResponse, binding: str
128143
) -> "MockAuthnResponse": # type: ignore # noqa: F821
@@ -447,6 +462,29 @@ def test_extract_user_identity_success():
447462
assert result["user_identity"] == get_user_identity()
448463

449464

465+
def test_extract_user_identity_with_slashed_attribute_keys_success(settings: SettingsWrapper):
466+
"""Test extract_user_identity function to verify if it correctly extracts user identity
467+
information from a (pysaml2) parsed SAML response with slashed attribute keys."""
468+
settings.SAML2_AUTH = {
469+
"ATTRIBUTES_MAP": {
470+
"email": "http://schemas.org/user/claim2.0/email",
471+
"username": "http://schemas.org/user/username",
472+
"first_name": "http://schemas.org/user/claim2.0/first_name",
473+
"last_name": "http://schemas.org/user/claim2.0/last_name",
474+
"token": "http://schemas.org/auth/server/token",
475+
}
476+
}
477+
478+
result = extract_user_identity(get_user_identify_with_slashed_keys()) # type: ignore
479+
480+
assert len(result) == 6
481+
assert result["username"] == result["email"] == "[email protected]"
482+
assert result["first_name"] == "John"
483+
assert result["last_name"] == "Doe"
484+
assert result["token"] == "TOKEN"
485+
assert result["user_identity"] == get_user_identify_with_slashed_keys()
486+
487+
450488
def test_extract_user_identity_token_not_required(settings: SettingsWrapper):
451489
"""Test extract_user_identity function to verify if it correctly extracts user identity
452490
information from a (pysaml2) parsed SAML response when token is not required."""

0 commit comments

Comments
 (0)