From 57eafdde246546a14762a26e02e88d3dc12017e0 Mon Sep 17 00:00:00 2001 From: Freebuu Date: Tue, 2 Apr 2024 13:28:40 +0300 Subject: [PATCH 1/4] add HasClaim constraint --- docs/validating-tokens.md | 1 + src/Validation/Constraint/HasClaim.php | 30 ++++++++++++ tests/Validation/Constraint/HasClaimTest.php | 49 ++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/Validation/Constraint/HasClaim.php create mode 100644 tests/Validation/Constraint/HasClaimTest.php diff --git a/docs/validating-tokens.md b/docs/validating-tokens.md index fb5190a9..8278ed2e 100644 --- a/docs/validating-tokens.md +++ b/docs/validating-tokens.md @@ -90,5 +90,6 @@ This library provides the following constraints: * `Lcobucci\JWT\Validation\Constraint\StrictValidAt`: verifies presence and validity of the claims `iat`, `nbf`, and `exp` (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\LooseValidAt`: verifies the claims `iat`, `nbf`, and `exp`, when present (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\HasClaimWithValue`: verifies that a **custom claim** has the expected value (not recommended when comparing cryptographic hashes) +* `Lcobucci\JWT\Validation\Constraint\HasClaim`: verifies that a claim is present You may also create your [own validation constraints](extending-the-library.md#validation-constraints). diff --git a/src/Validation/Constraint/HasClaim.php b/src/Validation/Constraint/HasClaim.php new file mode 100644 index 00000000..1fc8cd41 --- /dev/null +++ b/src/Validation/Constraint/HasClaim.php @@ -0,0 +1,30 @@ +claims(); + + if (! $claims->has($this->claim)) { + throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this); + } + } +} diff --git a/tests/Validation/Constraint/HasClaimTest.php b/tests/Validation/Constraint/HasClaimTest.php new file mode 100644 index 00000000..25c72345 --- /dev/null +++ b/tests/Validation/Constraint/HasClaimTest.php @@ -0,0 +1,49 @@ +expectException(ConstraintViolation::class); + $this->expectExceptionMessage('The token does not have the claim "claimId"'); + + $constraint = new HasClaim('claimId'); + $constraint->assert($this->buildToken()); + } + + /** @test */ + public function assertShouldRaiseExceptionWhenTokenIsNotAPlainToken(): void + { + $this->expectException(ConstraintViolation::class); + $this->expectExceptionMessage('You should pass a plain token'); + + $constraint = new HasClaim('claimId'); + $constraint->assert($this->createMock(Token::class)); + } + + /** @test */ + public function assertShouldNotRaiseExceptionWhenClaimMatches(): void + { + $token = $this->buildToken(['claimId' => 'claimValue']); + $constraint = new HasClaim('claimId'); + + $constraint->assert($token); + $this->addToAssertionCount(1); + } +} From 5be1d1680ee50719dbb31d7565048983b3ebea19 Mon Sep 17 00:00:00 2001 From: Freebuu Date: Tue, 2 Apr 2024 13:59:29 +0300 Subject: [PATCH 2/4] check RegisteredClaims in HasClaim --- src/Validation/Constraint/HasClaim.php | 5 ++++ tests/Validation/Constraint/HasClaimTest.php | 27 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Validation/Constraint/HasClaim.php b/src/Validation/Constraint/HasClaim.php index 1fc8cd41..c7b674ba 100644 --- a/src/Validation/Constraint/HasClaim.php +++ b/src/Validation/Constraint/HasClaim.php @@ -8,11 +8,16 @@ use Lcobucci\JWT\Validation\Constraint; use Lcobucci\JWT\Validation\ConstraintViolation; +use function in_array; + final class HasClaim implements Constraint { /** @param non-empty-string $claim */ public function __construct(private readonly string $claim) { + if (in_array($claim, Token\RegisteredClaims::ALL, true)) { + throw CannotValidateARegisteredClaim::create($claim); + } } public function assert(Token $token): void diff --git a/tests/Validation/Constraint/HasClaimTest.php b/tests/Validation/Constraint/HasClaimTest.php index 25c72345..949c2eed 100644 --- a/tests/Validation/Constraint/HasClaimTest.php +++ b/tests/Validation/Constraint/HasClaimTest.php @@ -4,6 +4,7 @@ namespace Lcobucci\JWT\Tests\Validation\Constraint; use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint\CannotValidateARegisteredClaim; use Lcobucci\JWT\Validation\Constraint\HasClaim; use Lcobucci\JWT\Validation\ConstraintViolation; @@ -17,6 +18,32 @@ */ final class HasClaimTest extends ConstraintTestCase { + /** + * @test + * @dataProvider registeredClaims + * + * @covers \Lcobucci\JWT\Validation\Constraint\CannotValidateARegisteredClaim + * + * @param non-empty-string $claim + */ + public function registeredClaimsCannotBeValidatedUsingThisConstraint(string $claim): void + { + $this->expectException(CannotValidateARegisteredClaim::class); + $this->expectExceptionMessage( + 'The claim "' . $claim . '" is a registered claim, another constraint must be used to validate its value', + ); + + new HasClaim($claim); + } + + /** @return iterable */ + public static function registeredClaims(): iterable + { + foreach (Token\RegisteredClaims::ALL as $claim) { + yield $claim => [$claim]; + } + } + /** @test */ public function assertShouldRaiseExceptionWhenClaimIsNotSet(): void { From 8f564c642453f411ac7e1e49cec1ec57313b5bd6 Mon Sep 17 00:00:00 2001 From: Freebuu Date: Wed, 3 Apr 2024 11:43:16 +0300 Subject: [PATCH 3/4] fix test assertion --- tests/Validation/Constraint/HasClaimTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/Validation/Constraint/HasClaimTest.php b/tests/Validation/Constraint/HasClaimTest.php index 949c2eed..df9ec51c 100644 --- a/tests/Validation/Constraint/HasClaimTest.php +++ b/tests/Validation/Constraint/HasClaimTest.php @@ -47,21 +47,24 @@ public static function registeredClaims(): iterable /** @test */ public function assertShouldRaiseExceptionWhenClaimIsNotSet(): void { + $constraint = new HasClaim('claimId'); + $this->expectException(ConstraintViolation::class); $this->expectExceptionMessage('The token does not have the claim "claimId"'); - $constraint = new HasClaim('claimId'); $constraint->assert($this->buildToken()); } /** @test */ public function assertShouldRaiseExceptionWhenTokenIsNotAPlainToken(): void { + $token = $this->createMock(Token::class); + $constraint = new HasClaim('claimId'); + $this->expectException(ConstraintViolation::class); $this->expectExceptionMessage('You should pass a plain token'); - $constraint = new HasClaim('claimId'); - $constraint->assert($this->createMock(Token::class)); + $constraint->assert($token); } /** @test */ From ca8d773dfa8817d6a13c32afcd5d5efecfe1bd37 Mon Sep 17 00:00:00 2001 From: Freebuu Date: Wed, 3 Apr 2024 11:57:40 +0300 Subject: [PATCH 4/4] update docs for custom claims --- docs/validating-tokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/validating-tokens.md b/docs/validating-tokens.md index 8278ed2e..6e3096c3 100644 --- a/docs/validating-tokens.md +++ b/docs/validating-tokens.md @@ -90,6 +90,6 @@ This library provides the following constraints: * `Lcobucci\JWT\Validation\Constraint\StrictValidAt`: verifies presence and validity of the claims `iat`, `nbf`, and `exp` (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\LooseValidAt`: verifies the claims `iat`, `nbf`, and `exp`, when present (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\HasClaimWithValue`: verifies that a **custom claim** has the expected value (not recommended when comparing cryptographic hashes) -* `Lcobucci\JWT\Validation\Constraint\HasClaim`: verifies that a claim is present +* `Lcobucci\JWT\Validation\Constraint\HasClaim`: verifies that a **custom claim** is present You may also create your [own validation constraints](extending-the-library.md#validation-constraints).