Skip to content

Commit

Permalink
WIP Trust Mark validation
Browse files Browse the repository at this point in the history
  • Loading branch information
cicnavi committed Jan 30, 2025
1 parent aba66cb commit c77b0f4
Show file tree
Hide file tree
Showing 67 changed files with 1,339 additions and 805 deletions.
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
"vendor/bin/phpunit --no-coverage",
"composer update web-token/jwt-framework --with web-token/jwt-framework:^4.0",
"vendor/bin/phpstan",
"vendor/bin/phpunit --no-coverage",
"vendor/bin/rector --dry-run"
"vendor/bin/phpunit",
"vendor/bin/rector --dry-run",
"vendor/bin/phpstan analyze -c phpstan-dev.neon --memory-limit=1024M"
]
}
}
4 changes: 2 additions & 2 deletions phpstan-dev.neon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

parameters:
level: 0
level: 4
paths:
- tests
tmpDir: build/phpstan
tmpDir: build/phpstan/dev
3 changes: 3 additions & 0 deletions src/Claims/GenericClaim.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

class GenericClaim
{
/**
* @param non-empty-string $name
*/
public function __construct(
protected readonly string $name,
protected readonly mixed $value,
Expand Down
36 changes: 36 additions & 0 deletions src/Claims/JwksClaim.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\OpenID\Claims;

use SimpleSAML\OpenID\Codebooks\ClaimsEnum;

class JwksClaim
{
/**
* @param array{keys:non-empty-array<array<string,mixed>>} $value
* @param non-empty-string $key
*/
public function __construct(
protected readonly array $value,
protected readonly string $key = ClaimsEnum::Jwks->value,
) {
}

/**
* @return array{keys:non-empty-array<array<string,mixed>>}
*/
public function getValue(): array
{
return $this->value;
}

/**
* @return non-empty-string
*/
public function getKey(): string
{
return $this->key;
}
}
1 change: 1 addition & 0 deletions src/Codebooks/ClaimsEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ enum ClaimsEnum: string
case Typ = 'typ';
case TrustChain = 'trust_chain';
case TrustMark = 'trust_mark';
case TrustMarkOwners = 'trust_mark_owners';
case TrustMarks = 'trust_marks';
case UserinfoEndpoint = 'userinfo_endpoint';
}
11 changes: 11 additions & 0 deletions src/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use SimpleSAML\OpenID\Core\Factories\RequestObjectFactory;
use SimpleSAML\OpenID\Decorators\DateIntervalDecorator;
use SimpleSAML\OpenID\Factories\AlgorithmManagerDecoratorFactory;
use SimpleSAML\OpenID\Factories\ClaimFactory;
use SimpleSAML\OpenID\Factories\DateIntervalDecoratorFactory;
use SimpleSAML\OpenID\Factories\JwsSerializerManagerDecoratorFactory;
use SimpleSAML\OpenID\Jwks\Factories\JwksFactory;
Expand All @@ -36,6 +37,7 @@ class Core
protected ?JwsVerifierDecoratorFactory $jwsVerifierDecoratorFactory = null;
protected ?JwksFactory $jwksFactory = null;
protected ?DateIntervalDecoratorFactory $dateIntervalDecoratorFactory = null;
protected ?ClaimFactory $claimFactory = null;

public function __construct(
protected readonly SupportedAlgorithms $supportedAlgorithms = new SupportedAlgorithms(
Expand All @@ -61,6 +63,7 @@ public function requestObjectFactory(): RequestObjectFactory
$this->jwsSerializerManagerDecorator(),
$this->timestampValidationLeewayDecorator,
$this->helpers(),
$this->claimFactory(),
);
}

Expand All @@ -73,6 +76,7 @@ public function clientAssertionFactory(): ClientAssertionFactory
$this->jwsSerializerManagerDecorator(),
$this->timestampValidationLeewayDecorator,
$this->helpers(),
$this->claimFactory(),
);
}

Expand Down Expand Up @@ -153,4 +157,11 @@ public function jwsVerifierDecorator(): JwsVerifierDecorator
}
return $this->jwsVerifierDecorator;
}

public function claimFactory(): ClaimFactory
{
return $this->claimFactory ??= new ClaimFactory(
$this->helpers(),
);
}
}
1 change: 1 addition & 0 deletions src/Core/Factories/ClientAssertionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function fromToken(string $token): ClientAssertion
$this->jwsSerializerManagerDecorator,
$this->timestampValidationLeeway,
$this->helpers,
$this->claimFactory,
);
}
}
1 change: 1 addition & 0 deletions src/Core/Factories/RequestObjectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function fromToken(string $token): RequestObject
$this->jwsSerializerManagerDecorator,
$this->timestampValidationLeeway,
$this->helpers,
$this->claimFactory,
);
}
}
9 changes: 0 additions & 9 deletions src/Exceptions/TrustMarkClaimException.php

This file was deleted.

51 changes: 50 additions & 1 deletion src/Factories/ClaimFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,72 @@
namespace SimpleSAML\OpenID\Factories;

use SimpleSAML\OpenID\Claims\GenericClaim;
use SimpleSAML\OpenID\Claims\JwksClaim;
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
use SimpleSAML\OpenID\Exceptions\JwksException;
use SimpleSAML\OpenID\Federation\Factories\FederationClaimFactory;
use SimpleSAML\OpenID\Helpers;

class ClaimFactory
{
protected FederationClaimFactory $federationClaimFactory;

public function __construct(
protected readonly Helpers $helpers,
) {
}

public function forFederation(): FederationClaimFactory
{
return $this->federationClaimFactory ??= new FederationClaimFactory(
$this->helpers,
$this,
);
}

/**
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
*/
public function buildGeneric(mixed $key, mixed $value): GenericClaim
{
return new GenericClaim(
$this->helpers->type()->ensureString($key, 'ClaimKey'),
$this->helpers->type()->ensureNonEmptyString($key, 'ClaimKey'),
$value,
);
}

/**
* @throws \SimpleSAML\OpenID\Exceptions\JwksException
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
*/
public function buildJwks(mixed $jwks, string $key = ClaimsEnum::Jwks->value): JwksClaim
{
if (
!is_array($jwks) ||
!array_key_exists(ClaimsEnum::Keys->value, $jwks) ||
!is_array($jwks[ClaimsEnum::Keys->value]) ||
(empty($jwks[ClaimsEnum::Keys->value]))
) {
throw new JwksException('Invalid JWKS encountered: ' . var_export($jwks, true));
}

$ensuredKeys = [];

foreach ($jwks[ClaimsEnum::Keys->value] as $index => $key) {
if (!is_array($key)) {
throw new JwksException(
sprintf('Unexpected JWKS key format: %s.', var_export($key, true)),
);
}

$ensuredKeys[$index] = $this->helpers->type()->ensureArrayWithKeysAsStrings($key);
}

$jwks[ClaimsEnum::Keys->value] = $ensuredKeys;

return new JwksClaim(
$jwks,
$this->helpers->type()->ensureNonEmptyString($key, 'ClaimKey'),
);
}
}
31 changes: 12 additions & 19 deletions src/Federation.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
use SimpleSAML\OpenID\Decorators\HttpClientDecorator;
use SimpleSAML\OpenID\Factories\AlgorithmManagerDecoratorFactory;
use SimpleSAML\OpenID\Factories\CacheDecoratorFactory;
use SimpleSAML\OpenID\Factories\ClaimFactory;
use SimpleSAML\OpenID\Factories\DateIntervalDecoratorFactory;
use SimpleSAML\OpenID\Factories\HttpClientDecoratorFactory;
use SimpleSAML\OpenID\Factories\JwsSerializerManagerDecoratorFactory;
use SimpleSAML\OpenID\Federation\EntityStatement\Factories\TrustMarkClaimBagFactory;
use SimpleSAML\OpenID\Federation\EntityStatement\Factories\TrustMarkClaimFactory;
use SimpleSAML\OpenID\Federation\EntityStatementFetcher;
use SimpleSAML\OpenID\Federation\Factories\EntityStatementFactory;
use SimpleSAML\OpenID\Federation\Factories\RequestObjectFactory;
Expand Down Expand Up @@ -53,8 +52,6 @@ class Federation
protected ?EntityStatementFactory $entityStatementFactory = null;
protected ?RequestObjectFactory $requestObjectFactory = null;
protected ?TrustMarkFactory $trustMarkFactory = null;
protected ?TrustMarkClaimFactory $trustMarkClaimFactory = null;
protected ?TrustMarkClaimBagFactory $trustMarkClaimBagFactory = null;
protected ?Helpers $helpers = null;
protected ?AlgorithmManagerDecoratorFactory $algorithmManagerDecoratorFactory = null;
protected ?JwsSerializerManagerDecoratorFactory $jwsSerializerManagerDecoratorFactory = null;
Expand All @@ -66,6 +63,7 @@ class Federation
protected ?TrustChainBagFactory $trustChainBagFactory = null;
protected ?CacheDecoratorFactory $cacheDecoratorFactory = null;
protected ?ArtifactFetcher $artifactFetcher = null;
protected ?ClaimFactory $claimFactory = null;

public function __construct(
protected readonly SupportedAlgorithms $supportedAlgorithms = new SupportedAlgorithms(),
Expand Down Expand Up @@ -157,8 +155,7 @@ public function entityStatementFactory(): EntityStatementFactory
$this->jwsSerializerManagerDecorator(),
$this->timestampValidationLeewayDecorator,
$this->helpers(),
$this->trustMarkClaimFactory(),
$this->trustMarkClaimBagFactory(),
$this->claimFactory(),
);
}

Expand All @@ -171,6 +168,7 @@ public function requestObjectFactory(): RequestObjectFactory
$this->jwsSerializerManagerDecorator(),
$this->timestampValidationLeewayDecorator,
$this->helpers(),
$this->claimFactory(),
);
}

Expand All @@ -183,14 +181,7 @@ public function trustMarkFactory(): TrustMarkFactory
$this->jwsSerializerManagerDecorator(),
$this->timestampValidationLeewayDecorator,
$this->helpers(),
);
}

public function trustMarkClaimFactory(): TrustMarkClaimFactory
{
return $this->trustMarkClaimFactory ??= new TrustMarkClaimFactory(
$this->trustMarkFactory(),
$this->helpers(),
$this->claimFactory(),
);
}

Expand Down Expand Up @@ -256,11 +247,6 @@ public function cacheDecoratorFactory(): CacheDecoratorFactory
return $this->cacheDecoratorFactory;
}

public function trustMarkClaimBagFactory(): TrustMarkClaimBagFactory
{
return $this->trustMarkClaimBagFactory ??= new TrustMarkClaimBagFactory();
}

public function maxCacheDurationDecorator(): DateIntervalDecorator
{
return $this->maxCacheDurationDecorator;
Expand Down Expand Up @@ -294,4 +280,11 @@ public function artifactFetcher(): ArtifactFetcher
$this->logger,
);
}

public function claimFactory(): ClaimFactory
{
return $this->claimFactory ??= new ClaimFactory(
$this->helpers(),
);
}
}
58 changes: 58 additions & 0 deletions src/Federation/Claims/TrustMarkOwnersClaimBag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\OpenID\Federation\Claims;

use JsonSerializable;

class TrustMarkOwnersClaimBag implements JsonSerializable
{
/** @var array<non-empty-string,\SimpleSAML\OpenID\Federation\Claims\TrustMarkOwnersClaimValue> */
protected array $trustMarkOwnersClaimValues = [];

public function __construct(TrustMarkOwnersClaimValue ...$trustMarkOwnersClaimValues)
{
$this->add(...$trustMarkOwnersClaimValues);
}

public function add(TrustMarkOwnersClaimValue ...$trustMarkOwnersClaimValues): void
{
foreach ($trustMarkOwnersClaimValues as $trustMarkOwnersClaimValue) {
$this->trustMarkOwnersClaimValues[$trustMarkOwnersClaimValue->getTrustMarkId()] =
$trustMarkOwnersClaimValue;
}
}

public function has(string $trustMarkId): bool
{
return isset($this->trustMarkOwnersClaimValues[$trustMarkId]);
}

public function get(string $trustMarkId): ?TrustMarkOwnersClaimValue
{
return $this->trustMarkOwnersClaimValues[$trustMarkId] ?? null;
}

/**
* @return array<non-empty-string,\SimpleSAML\OpenID\Federation\Claims\TrustMarkOwnersClaimValue>
*/
public function getAll(): array
{
return $this->trustMarkOwnersClaimValues;
}

/**
* @return array<non-empty-string,array<non-empty-string,mixed>>
*/
public function jsonSerialize(): array
{
return array_combine(
array_keys($this->trustMarkOwnersClaimValues),
array_map(
fn(TrustMarkOwnersClaimValue $tMOCValue): array => $tMOCValue->jsonSerialize(),
$this->trustMarkOwnersClaimValues,
),
);
}
}
Loading

0 comments on commit c77b0f4

Please sign in to comment.