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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# TODO
- upgrade to v9 of oauth2-server https://github.com/thephpleague/oauth2-server/releases/tag/9.0.0
- implement key rollover
- implement token introspection
- implement dynamic client registration
- move request rules to templates (generics) for proper static type handling

- remove dependency on laminas/laminas-httphandlerrunner
- create a bridge towards SSP utility classes, so they can be easily mocked
- move away from SSP database as store; move to DBAL
Expand Down Expand Up @@ -51,6 +47,7 @@ and optionally a port (as in all previous module versions).
- authority hints
- federation caching adapter and its arguments
- PKI keys - federation keys used for example to sign federation entity statements
- federation participation limiting based on Trust Marks for RPs
- signer algorithm
- entity statement duration
- organization name
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@
},
"scripts": {
"pre-commit": [
"vendor/bin/phpcbf",
"vendor/bin/phpcs -p",
"vendor/bin/psalm",
"vendor/bin/phpcs -p"
"vendor/bin/phpunit"
],
"tests": [
"vendor/bin/phpunit --no-coverage"
Expand Down
3 changes: 3 additions & 0 deletions routing/routes/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
$routes->add(RoutesEnum::AdminTestTrustChainResolution->name, RoutesEnum::AdminTestTrustChainResolution->value)
->controller([TestController::class, 'trustChainResolution'])
->methods([HttpMethodsEnum::GET->value, HttpMethodsEnum::POST->value]);
$routes->add(RoutesEnum::AdminTestTrustMarkValidation->name, RoutesEnum::AdminTestTrustMarkValidation->value)
->controller([TestController::class, 'trustMarkValidation'])
->methods([HttpMethodsEnum::GET->value, HttpMethodsEnum::POST->value]);

/*****************************************************************************************************************
* OpenID Connect
Expand Down
1 change: 1 addition & 0 deletions src/Codebooks/RoutesEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum RoutesEnum: string

// Testing
case AdminTestTrustChainResolution = 'admin/test/trust-chain-resolution';
case AdminTestTrustMarkValidation = 'admin/test/trust-mark-validation';


/*****************************************************************************************************************
Expand Down
81 changes: 71 additions & 10 deletions src/Controllers/Admin/TestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

class TestController
{
protected readonly Federation $federationWithArrayLogger;

public function __construct(
protected readonly ModuleConfig $moduleConfig,
protected readonly TemplateFactory $templateFactory,
Expand All @@ -28,6 +30,14 @@ public function __construct(
protected readonly ArrayLogger $arrayLogger,
) {
$this->authorization->requireAdmin(true);

$this->arrayLogger->setWeight(ArrayLogger::WEIGHT_WARNING);
// Let's create new Federation instance so we can inject our debug logger and go without cache.
$this->federationWithArrayLogger = new Federation(
supportedAlgorithms: $this->federation->supportedAlgorithms(),
cache: null,
logger: $this->arrayLogger,
);
}

/**
Expand All @@ -37,14 +47,6 @@ public function __construct(
*/
public function trustChainResolution(Request $request): Response
{
$this->arrayLogger->setWeight(ArrayLogger::WEIGHT_WARNING);
// Let's create new Federation instance so we can inject our debug logger and go without cache.
$federation = new Federation(
supportedAlgorithms: $this->federation->supportedAlgorithms(),
cache: null,
logger: $this->arrayLogger,
);

$leafEntityId = $this->moduleConfig->getIssuer();
$trustChainBag = null;
$resolvedMetadata = [];
Expand All @@ -69,7 +71,8 @@ public function trustChainResolution(Request $request): Response
$trustAnchorIds = $this->helpers->str()->convertTextToArray($rawTrustAnchorIds);

try {
$trustChainBag = $federation->trustChainResolver()->for($leafEntityId, $trustAnchorIds);
$trustChainBag = $this->federationWithArrayLogger->trustChainResolver()
->for($leafEntityId, $trustAnchorIds);

foreach ($trustChainBag->getAll() as $index => $trustChain) {
$metadataEntries = [];
Expand All @@ -94,7 +97,7 @@ public function trustChainResolution(Request $request): Response

$trustAnchorIds = implode("\n", $trustAnchorIds);
$logMessages = $this->arrayLogger->getEntries();
//dd($this->arrayLogger->getEntries());

return $this->templateFactory->build(
'oidc:tests/trust-chain-resolution.twig',
compact(
Expand All @@ -108,4 +111,62 @@ public function trustChainResolution(Request $request): Response
RoutesEnum::AdminTestTrustChainResolution->value,
);
}

public function trustMarkValidation(Request $request): Response
{
$trustMarkId = null;
$leafEntityId = null;
$trustAnchorId = null;
$isFormSubmitted = false;

if ($request->isMethod(Request::METHOD_POST)) {
$isFormSubmitted = true;

!empty($trustMarkId = $request->request->getString('trustMarkId')) ||
throw new OidcException('Empty Trust Mark ID.');
!empty($leafEntityId = $request->request->getString('leafEntityId')) ||
throw new OidcException('Empty leaf entity ID.');
!empty($trustAnchorId = $request->request->getString('trustAnchorId')) ||
throw new OidcException('Empty Trust Anchor ID.');

try {
// We should not try to validate Trust Marks until we have resolved trust chain between leaf and TA.
$trustChain = $this->federation->trustChainResolver()->for(
$leafEntityId,
[$trustAnchorId],
)->getShortest();

try {
$this->federationWithArrayLogger->trustMarkValidator()->doForTrustMarkId(
$trustMarkId,
$trustChain->getResolvedLeaf(),
$trustChain->getResolvedTrustAnchor(),
);
} catch (\Throwable $exception) {
$this->arrayLogger->error('Trust Mark validation error: ' . $exception->getMessage());
}
} catch (TrustChainException $exception) {
$this->arrayLogger->error(sprintf(
'Could not resolve Trust Chain for leaf entity %s under Trust Anchor %s. Error was %s',
$leafEntityId,
$trustAnchorId,
$exception->getMessage(),
));
}
}

$logMessages = $this->arrayLogger->getEntries();

return $this->templateFactory->build(
'oidc:tests/trust-mark-validation.twig',
compact(
'trustMarkId',
'leafEntityId',
'trustAnchorId',
'logMessages',
'isFormSubmitted',
),
RoutesEnum::AdminTestTrustMarkValidation->value,
);
}
}
35 changes: 28 additions & 7 deletions src/Controllers/Federation/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use SimpleSAML\Module\oidc\Factories\Entities\ClientEntityFactory;
use SimpleSAML\Module\oidc\Services\LoggerService;
use SimpleSAML\Module\oidc\Utils\FederationCache;
use SimpleSAML\Module\oidc\Utils\FederationParticipationValidator;
use SimpleSAML\Module\oidc\Utils\ProtocolCache;
use SimpleSAML\OpenID\Codebooks\EntityTypesEnum;
use SimpleSAML\OpenID\Core;
Expand All @@ -37,6 +38,7 @@ public function __construct(
protected Database $database,
protected ClientEntityFactory $clientEntityFactory,
protected CoreFactory $coreFactory,
protected FederationParticipationValidator $federationParticipationValidator,
protected \DateInterval $maxCacheDuration = new \DateInterval('PT30S'),
) {
}
Expand Down Expand Up @@ -70,21 +72,40 @@ public function __invoke(): Response
$trustChain = $this->federation
->trustChainResolver()
->for(
// 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ALeaf/',
'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ALeaf/',
// 'https://trust-anchor.testbed.oidcfed.incubator.geant.org/oidc/rp/',
// 'https://relying-party-php.testbed.oidcfed.incubator.geant.org/',
'https://gorp.testbed.oidcfed.incubator.geant.org',
// 'https://gorp.testbed.oidcfed.incubator.geant.org',
// 'https://maiv1.incubator.geant.org',
[
'https://trust-anchor.testbed.oidcfed.incubator.geant.org/',
// 'https://trust-anchor.testbed.oidcfed.incubator.geant.org/',
'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ABTrustAnchor/',
'https://08-dap.localhost.markoivancic.from.hr/openid/entities/CTrustAnchor/',
// 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/CTrustAnchor/',
],
)->getAll();
dd($trustChain);
)
//->getAll();
->getShortestByTrustAnchorPriority(
'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ABTrustAnchor/',
);

$leaf = $trustChain->getResolvedLeaf();
$trustAnchor = $trustChain->getResolvedTrustAnchor();

$this->federationParticipationValidator->validateForAllOfLimit(
['https://08-dap.localhost.markoivancic.from.hr/openid/entities/ATrustMarkIssuer/trust-mark/member'],
$leaf,
$trustAnchor,
);

dd($leaf->getPayload());
$leafFederationJwks = $leaf->getJwks();

$this->federation->trustMarkValidator()->fromCacheOrDoForTrustMarkId(
'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ATrustMarkIssuer/trust-mark/member',
$leaf,
$trustAnchor,
);

// $leafFederationJwks = $leaf->getJwks();
// dd($leafFederationJwks);
// /** @psalm-suppress PossiblyNullArgument */
$resolvedMetadata = $trustChain->getResolvedMetadata(EntityTypesEnum::OpenIdRelyingParty);
Expand Down
7 changes: 7 additions & 0 deletions src/Factories/TemplateFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ protected function includeDefaultMenuItems(): void
Translate::noop('Test Trust Chain Resolution'),
),
);

$this->oidcMenu->addItem(
$this->oidcMenu->buildItem(
$this->moduleConfig->getModuleUrl(RoutesEnum::AdminTestTrustMarkValidation->value),
Translate::noop('Test Trust Mark Validation'),
),
);
}

public function setShowMenu(bool $showMenu): TemplateFactory
Expand Down
16 changes: 14 additions & 2 deletions src/Server/RequestRules/Rules/ClientIdRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ public function __construct(

/**
* @inheritDoc
* @throws \JsonException
* @throws \League\OAuth2\Server\Exception\OAuthServerException
* @throws \Psr\SimpleCache\InvalidArgumentException
* @throws \SimpleSAML\Error\ConfigurationError
* @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException
* @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
* @throws \SimpleSAML\OpenID\Exceptions\JwksException
* @throws \SimpleSAML\OpenID\Exceptions\JwsException
* @throws \SimpleSAML\OpenID\Exceptions\RequestObjectException
* @throws \SimpleSAML\OpenID\Exceptions\TrustChainException
* @throws \SimpleSAML\OpenID\Exceptions\TrustMarkException
*/
public function checkRule(
ServerRequestInterface $request,
Expand Down Expand Up @@ -196,7 +208,7 @@ public function checkRule(
$this->helpers->dateTime()->getFromTimestamp($trustChain->getResolvedExpirationTime()),
$existingClient,
$clientEntityId,
$clientFederationEntity->getJwks(),
$clientFederationEntity->getJwks()->getValue(),
$request,
);

Expand All @@ -209,7 +221,7 @@ public function checkRule(
// Check if federation participation is limited by Trust Marks.
if (
$this->moduleConfig->isFederationParticipationLimitedByTrustMarksFor(
$trustChain->getResolvedTrustAnchor()->getIssuer(),
$trustAnchorEntityConfiguration->getIssuer(),
)
) {
$this->federationParticipationValidator->byTrustMarksFor($trustChain);
Expand Down
2 changes: 1 addition & 1 deletion src/Server/Validators/BearerTokenValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ protected function initJwtConfiguration(): void
InMemory::plainText('empty', 'empty'),
);

/** @psalm-suppress ArgumentTypeCoercion */
/** @psalm-suppress DeprecatedMethod, ArgumentTypeCoercion */
$this->jwtConfiguration->setValidationConstraints(
new StrictValidAt(new SystemClock(new DateTimeZone(date_default_timezone_get()))),
new SignedWith(
Expand Down
1 change: 1 addition & 0 deletions src/Services/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ public function __construct()
$this->services[JwksResolver::class] = $jwksResolver;
$federationParticipationValidator = new FederationParticipationValidator(
$moduleConfig,
$federation,
$loggerService,
);
$this->services[FederationParticipationValidator::class] = $federationParticipationValidator;
Expand Down
Loading