Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/joserfc/_rfc7519/claims.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def convert_claims(claims: Claims, encoder_cls: type[JSONEncoder] | None = None)
class ClaimsOption(TypedDict, total=False):
essential: bool
allow_blank: bool | None
value: str | int | bool
value: str | int | bool | list[str | int | bool]
values: list[str | int | bool] | list[str] | list[int] | list[bool]


Expand Down Expand Up @@ -64,20 +64,25 @@ def check_value(self, claim_name: str, value: Any) -> None:

option_values = option.get("values")

if option_values is None:
option_value = option.get("value")
if option_value is not None:
option_values = [option_value]
if option_values:
if isinstance(value, list):
if not any(v in value for v in option_values):
raise InvalidClaimError(claim_name)
elif value not in option_values:
raise InvalidClaimError(claim_name)
return

if not option_values:
option_value = option.get("value")
if option_value is None:
return

# "value" is the expected claim value itself; a list claim also
# matches when one of its elements is the expected value
if isinstance(value, list):
if not any(v in value for v in option_values):
raise InvalidClaimError(claim_name)
else:
if value not in option_values:
if value != option_value and option_value not in value:
raise InvalidClaimError(claim_name)
elif value != option_value:
raise InvalidClaimError(claim_name)

def validate(self, claims: dict[str, Any]) -> None:
"""
Expand Down
16 changes: 16 additions & 0 deletions tests/jwt/test_claims.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ def test_option_value(self):
claims_requests.validate({"foo": False})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"foo": True})

def test_option_value_with_list(self):
# a list "value" is the expected claim value itself
claims_requests = jwt.JWTClaimsRegistry(aud={"essential": True, "value": ["id1"]})
claims_requests.validate({"aud": ["id1"]})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"aud": ["id2"]})

claims_requests = jwt.JWTClaimsRegistry(aud={"essential": True, "value": ["id1", "id2"]})
claims_requests.validate({"aud": ["id1", "id2"]})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"aud": "id1"})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"aud": ["id1"]})

# a scalar "value" still matches any element of a list claim
claims_requests = jwt.JWTClaimsRegistry(foo={"essential": True, "value": "id1"})
claims_requests.validate({"foo": ["id1"]})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"foo": ["id2"]})

def test_option_values(self):
claims_requests = jwt.JWTClaimsRegistry(foo={"essential": True, "values": ["1", "2", True, False]})
self.assertRaises(InvalidClaimError, claims_requests.validate, {"foo": "a"})
Expand Down
Loading