Skip to content

Commit 0e85d8d

Browse files
authored
Enable validating TMs using TMS endpoint (#13)
Enable validating Trust Marks using Trust Mark Status endpoint.
1 parent b46dba0 commit 0e85d8d

26 files changed

Lines changed: 1351 additions & 32 deletions

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,11 @@ try {
236236

237237
### Validating Trust Marks
238238

239-
Federation tools expose Trust Mark Validator with several methods for validating Trust Marks, with the most common
240-
one being the one to validate Trust Mark for some entity simply based on the Trust Mark Type.
239+
Federation tools expose Trust Mark Validator with several methods for validating
240+
Trust Marks, with the most common one being the one to validate Trust Mark for
241+
some entity simply based on the Trust Mark Type.
241242

242-
If cache is utilized, Trust Mark validation will be cached with cache TTL being the minimum expiration
243+
If cache is used, Trust Mark validation will be cached with cache TTL being the minimum expiration
243244
time of Trust Mark, Leaf Entity Statement or `maxCacheDuration`, whatever is smaller.
244245

245246
```php
@@ -257,20 +258,22 @@ $leafEntityConfigurationStatement = $trustChain->getResolvedLeaf();
257258
$trustAnchorConfigurationStatement = $trustChain->getResolvedTrustAnchor();
258259

259260
try {
260-
// Example which queries cache for previously validated Trust Mark, and does formal validation if not cached.
261+
// Example which queries cache for previously validated Trust Mark and does formal validation if not cached.
261262
$federationTools->trustMarkValidator()->fromCacheOrDoForTrustMarkType(
262263
$trustMarkType,
263264
$leafEntityConfigurationStatement,
264265
$trustAnchorConfigurationStatement,
265266
$expectedJwtType = \SimpleSAML\OpenID\Codebooks\JwtTypesEnum::TrustMarkJwt,
266267
);
267268

268-
// Example which always does formal validation (does not use cache).
269+
// Example which always does formal validation (does not use cache), and requires usage of Trust Mark
270+
// Status Endpoint for non-expiring Trust Marks.
269271
$federationTools->trustMarkValidator()->doForTrustMarkType(
270272
$trustMarkType,
271273
$leafEntityConfigurationStatement,
272274
$trustAnchorConfigurationStatement,
273275
$expectedJwtType = \SimpleSAML\OpenID\Codebooks\JwtTypesEnum::TrustMarkJwt,
276+
\SimpleSAML\OpenID\Codebooks\TrustMarkStatusEndpointUsagePolicyEnum::RequiredForNonExpiringTrustMarksOnly,
274277
);
275278
} catch (\Throwable $exception) {
276279
$this->logger->error('Trust Mark validation failed. Error was: ' . $exception->getMessage());

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"vendor/bin/phpcbf",
5252
"vendor/bin/phpcs -p",
5353
"composer update web-token/jwt-framework --with web-token/jwt-framework:^3.0",
54-
"vendor/bin/phpstan",
54+
"vendor/bin/phpstan --memory-limit=1024M",
5555
"vendor/bin/phpunit --no-coverage",
5656
"composer update web-token/jwt-framework --with web-token/jwt-framework:^4.0",
5757
"vendor/bin/phpstan",

src/Codebooks/ClaimsEnum.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ enum ClaimsEnum: string
5757
case FederationFetchEndpoint = 'federation_fetch_endpoint';
5858
case FederationListEndpoint = 'federation_list_endpoint';
5959
case FederationTrustMarkEndpoint = 'federation_trust_mark_endpoint';
60+
case FederationTrustMarkStatusEndpoint = 'federation_trust_mark_status_endpoint';
6061
case Format = 'format';
6162
case GrantTypes = 'grant_types';
6263
case GrantTypesSupported = 'grant_types_supported';
@@ -130,6 +131,7 @@ enum ClaimsEnum: string
130131
case ServiceDocumentation = 'service_documentation';
131132
case SignedJwksUri = 'signed_jwks_uri';
132133
case SignedMetadata = 'signed_metadata';
134+
case Status = 'status';
133135
// Subject
134136
case Sub = 'sub';
135137
case SubjectTypesSupported = 'subject_types_supported';

src/Codebooks/ContentTypesEnum.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ enum ContentTypesEnum: string
99
case ApplicationJwt = 'application/jwt';
1010
case ApplicationEntityStatementJwt = 'application/entity-statement+jwt';
1111
case ApplicationTrustMarkJwt = 'application/trust-mark+jwt';
12+
case ApplicationTrustMarkStatusResponseJwt = 'application/trust-mark-status-response+jwt';
1213
}

src/Codebooks/JwtTypesEnum.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ enum JwtTypesEnum: string
1010
case JwkSetJwt = 'jwk-set+jwt';
1111
case TrustMarkJwt = 'trust-mark+jwt';
1212
case TrustMarkDelegationJwt = 'trust-mark-delegation+jwt';
13+
case TrustMarkStatusResponseJwt = 'trust-mark-status-response+jwt';
1314
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\Codebooks;
6+
7+
/**
8+
* Trust Mark Status Endpoint Usage Policy for Trust Mark validation.
9+
*/
10+
enum TrustMarkStatusEndpointUsagePolicyEnum
11+
{
12+
// Trust Mark will always be checked using the Trust Mark Status Endpoint.
13+
// Trust Mark Status Endpoint must be exposed by Trust Mark Issuer.
14+
case Required;
15+
16+
// Trust Mark will be checked using the Trust Mark Status Endpoint if the
17+
// Trust Mark does not expire. Trust Mark Status Endpoint must be exposed
18+
// by Trust Mark Issuer.
19+
case RequiredForNonExpiringTrustMarksOnly;
20+
21+
// Trust Mark will be checked using the Trust Mark Status Endpoint if the
22+
// Trust Mark Issuer provides the endpoint.
23+
case RequiredIfEndpointProvided;
24+
25+
// Trust Mark will be checked using the Trust Mark Status Endpoint if the
26+
// Trust Mark does not expire and the Trust Mark Issuer provides the
27+
// endpoint.
28+
case RequiredIfEndpointProvidedForNonExpiringTrustMarksOnly;
29+
30+
// Trust Mark will not be checked using the Trust Mark Status Endpoint.
31+
case NotUsed;
32+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\Codebooks;
6+
7+
/**
8+
* https://openid.net/specs/openid-federation-1_0.html#name-trust-mark-status-response
9+
*/
10+
enum TrustMarkStatusEnum: string
11+
{
12+
case Active = 'active';
13+
case Expired = 'expired';
14+
case Revoked = 'revoked';
15+
case Invalid = 'invalid';
16+
17+
18+
public function isValid(): bool
19+
{
20+
return match ($this) {
21+
self::Active => true,
22+
default => false,
23+
};
24+
}
25+
}

src/Decorators/HttpClientDecorator.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ public function __construct(public readonly Client $client = new Client(self::DE
2222

2323

2424
/**
25+
* @param array<string, mixed> $options See https://docs.guzzlephp.org/en/stable/request-options.html
2526
* @throws \SimpleSAML\OpenID\Exceptions\HttpException
2627
*/
27-
public function request(HttpMethodsEnum $httpMethodsEnum, string $uri): ResponseInterface
28-
{
28+
public function request(
29+
HttpMethodsEnum $httpMethodsEnum,
30+
string $uri,
31+
array $options = [],
32+
): ResponseInterface {
2933
try {
30-
$response = $this->client->request($httpMethodsEnum->value, $uri);
34+
$response = $this->client->request($httpMethodsEnum->value, $uri, $options);
3135
} catch (Throwable $throwable) {
3236
$message = sprintf(
3337
'Error sending HTTP request to %s. Error was: %s',
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\OpenID\Exceptions;
6+
7+
class TrustMarkStatusException extends JwsException
8+
{
9+
}

src/Federation.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
use SimpleSAML\OpenID\Federation\Factories\TrustChainFactory;
2525
use SimpleSAML\OpenID\Federation\Factories\TrustMarkDelegationFactory;
2626
use SimpleSAML\OpenID\Federation\Factories\TrustMarkFactory;
27+
use SimpleSAML\OpenID\Federation\Factories\TrustMarkStatusFactory;
2728
use SimpleSAML\OpenID\Federation\MetadataPolicyApplicator;
2829
use SimpleSAML\OpenID\Federation\MetadataPolicyResolver;
2930
use SimpleSAML\OpenID\Federation\TrustChainResolver;
3031
use SimpleSAML\OpenID\Federation\TrustMarkFetcher;
32+
use SimpleSAML\OpenID\Federation\TrustMarkStatusFetcher;
3133
use SimpleSAML\OpenID\Federation\TrustMarkValidator;
3234
use SimpleSAML\OpenID\Jwks\Factories\JwksFactory;
3335
use SimpleSAML\OpenID\Jws\Factories\JwsParserFactory;
@@ -101,6 +103,10 @@ class Federation
101103

102104
protected ?TrustMarkFetcher $trustMarkFetcher = null;
103105

106+
protected ?TrustMarkStatusFactory $trustMarkStatusFactory = null;
107+
108+
protected ?TrustMarkStatusFetcher $trustMarkStatusFetcher = null;
109+
104110

105111
public function __construct(
106112
protected readonly SupportedAlgorithms $supportedAlgorithms = new SupportedAlgorithms(),
@@ -248,12 +254,39 @@ public function trustMarkDelegationFactory(): TrustMarkDelegationFactory
248254
}
249255

250256

257+
public function trustMarkStatusFactory(): TrustMarkStatusFactory
258+
{
259+
return $this->trustMarkStatusFactory ??= new TrustMarkStatusFactory(
260+
$this->jwsParser(),
261+
$this->jwsVerifierDecorator(),
262+
$this->jwksFactory(),
263+
$this->jwsSerializerManagerDecorator(),
264+
$this->timestampValidationLeewayDecorator,
265+
$this->helpers(),
266+
$this->claimFactory(),
267+
);
268+
}
269+
270+
271+
public function trustMarkStatusFetcher(): TrustMarkStatusFetcher
272+
{
273+
return $this->trustMarkStatusFetcher ??= new TrustMarkStatusFetcher(
274+
$this->trustMarkStatusFactory(),
275+
$this->artifactFetcher(),
276+
$this->maxCacheDurationDecorator,
277+
$this->helpers(),
278+
$this->logger,
279+
);
280+
}
281+
282+
251283
public function trustMarkValidator(): TrustMarkValidator
252284
{
253285
return $this->trustMarkValidator ??= new TrustMarkValidator(
254286
$this->trustChainResolver(),
255287
$this->trustMarkFactory(),
256288
$this->trustMarkDelegationFactory(),
289+
$this->trustMarkStatusFetcher(),
257290
$this->maxCacheDurationDecorator,
258291
$this->cacheDecorator(),
259292
$this->logger,

0 commit comments

Comments
 (0)