diff --git a/helusers/_oidc_auth_impl.py b/helusers/_oidc_auth_impl.py index f3d723d..f88602a 100644 --- a/helusers/_oidc_auth_impl.py +++ b/helusers/_oidc_auth_impl.py @@ -47,6 +47,14 @@ def authenticate(self, request): logger.debug("Invalid token signature") raise + # Some OPs may provide the "amr" incorrectly as a string, while the + # specification dictates it must be an array of strings. Fix that here. + if isinstance(payload.get("amr"), str): + payload["amr"] = [payload["amr"]] + logger.debug( + 'Modified "amr" claim to be an array of strings instead of a string.' + ) + logger.debug("Token payload decoded as: {}".format(payload)) self.validate_claims(payload) diff --git a/helusers/tests/test_oidc_api_token_authentication.py b/helusers/tests/test_oidc_api_token_authentication.py index 753f7c8..785a189 100644 --- a/helusers/tests/test_oidc_api_token_authentication.py +++ b/helusers/tests/test_oidc_api_token_authentication.py @@ -4,7 +4,7 @@ from helusers.oidc import ApiTokenAuthentication -from .conftest import encoded_jwt_factory, ISSUER1 +from .conftest import ISSUER1, encoded_jwt_factory @pytest.fixture(autouse=True) @@ -12,13 +12,14 @@ def auto_auth_server(auth_server): return auth_server -@pytest.mark.django_db -def test_valid_jwt_is_accepted(rf, unix_timestamp_now): - sut = ApiTokenAuthentication() +@pytest.fixture +def user_uuid(): + return uuid.UUID("b7a35517-eb1f-46c9-88bf-3206fb659c3c") - user_uuid = uuid.UUID("b7a35517-eb1f-46c9-88bf-3206fb659c3c") - encoded_jwt = encoded_jwt_factory( +@pytest.fixture +def jwt_data(user_uuid, unix_timestamp_now): + return dict( iss=ISSUER1, aud="test_audience", iat=unix_timestamp_now - 10, @@ -26,6 +27,22 @@ def test_valid_jwt_is_accepted(rf, unix_timestamp_now): sub=str(user_uuid), ) + +@pytest.mark.parametrize( + "jwt_data_extra", + [ + dict(), + dict(amr="something"), + dict(amr=["something"]), + ], +) +@pytest.mark.django_db +def test_valid_jwt_is_accepted(rf, jwt_data, user_uuid, jwt_data_extra): + sut = ApiTokenAuthentication() + + jwt_data.update(jwt_data_extra) + encoded_jwt = encoded_jwt_factory(**jwt_data) + request = rf.get("/path", HTTP_AUTHORIZATION=f"Bearer {encoded_jwt}") (user, auth) = sut.authenticate(request)