diff --git a/config-templates/module_oidc.php b/config-templates/module_oidc.php index f1fc032f..0b915221 100644 --- a/config-templates/module_oidc.php +++ b/config-templates/module_oidc.php @@ -355,6 +355,12 @@ //'https://intermediate.example.org/', ], + // (optional) Federation Trust Mark tokens. An array of tokens (signed JWTs), each representing a Trust Mark + // issued to this entity. + ModuleConfig::OPTION_FEDERATION_TRUST_MARK_TOKENS => [ +// 'eyJ...GHg', + ], + // (optional) Dedicated federation cache adapter, used to cache federation artifacts like trust chains, entity // statements, etc. It will also be used for token reuse check in federation context. Setting this option is // recommended in production environments. If set to null, no caching will be used. Can be set to any diff --git a/src/Controller/Federation/EntityStatementController.php b/src/Controller/Federation/EntityStatementController.php index 52c3d8b0..ea7b0be7 100644 --- a/src/Controller/Federation/EntityStatementController.php +++ b/src/Controller/Federation/EntityStatementController.php @@ -20,7 +20,7 @@ use SimpleSAML\OpenID\Codebooks\ErrorsEnum; use SimpleSAML\OpenID\Codebooks\HttpHeadersEnum; use SimpleSAML\OpenID\Codebooks\JwtTypesEnum; -use SimpleSAML\OpenID\Codebooks\RequestAuthenticationMethodsEnum; +use SimpleSAML\OpenID\Federation; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -40,6 +40,7 @@ public function __construct( private readonly OpMetadataService $opMetadataService, private readonly ClientRepository $clientRepository, private readonly Helpers $helpers, + private readonly Federation $federation, private readonly ?FederationCache $federationCache, ) { if (!$this->moduleConfig->getFederationEnabled()) { @@ -53,6 +54,8 @@ public function __construct( * @return \Symfony\Component\HttpFoundation\Response * @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException * @throws \ReflectionException + * @throws \SimpleSAML\OpenID\Exceptions\JwsException + * @throws \Psr\SimpleCache\InvalidArgumentException */ public function configuration(): Response { @@ -99,6 +102,7 @@ public function configuration(): Response //'federation_trust_mark_list_endpoint', //'federation_trust_mark_endpoint', //'federation_historical_keys_endpoint', + //'endpoint_auth_signing_alg_values_supported' // Common https://openid.net/specs/openid-federation-1_0.html#name-common-metadata-parameters //'signed_jwks_uri', //'jwks_uri', @@ -110,14 +114,6 @@ public function configuration(): Response ClaimsEnum::ClientRegistrationTypesSupported->value => [ ClientRegistrationTypesEnum::Automatic->value, ], - ClaimsEnum::RequestAuthenticationMethodsSupported->value => [ - ClaimsEnum::AuthorizationEndpoint->value => [ - RequestAuthenticationMethodsEnum::RequestObject->value, - ], - ], - ClaimsEnum::RequestAuthenticationSigningAlgValuesSupported->value => [ - $this->moduleConfig->getProtocolSigner()->algorithmId(), - ], ], ], ); @@ -129,14 +125,32 @@ public function configuration(): Response $builder = $builder->withClaim(ClaimsEnum::AuthorityHints->value, $authorityHints); } + if ( + is_array($trustMarkTokens = $this->moduleConfig->getFederationTrustMarkTokens()) && + (!empty($trustMarkTokens)) + ) { + $trustMarks = array_map(function (string $token): array { + $trustMarkEntity = $this->federation->trustMarkFactory()->fromToken($token); + + if ($trustMarkEntity->getSubject() !== $this->moduleConfig->getIssuer()) { + throw OidcServerException::serverError(sprintf( + 'Trust Mark %s is not intended for this entity.', + $trustMarkEntity->getIdentifier(), + )); + } + + return [ + ClaimsEnum::Id->value => $trustMarkEntity->getIdentifier(), + ClaimsEnum::TrustMark->value => $token, + ]; + }, $trustMarkTokens); + + $builder = $builder->withClaim(ClaimsEnum::TrustMarks->value, $trustMarks); + } + + // TODO mivanci Continue // Remaining claims, add if / when ready. // * crit - // * trust_marks - // * trust_mark_issuers - // * source_endpoint - - // Note: claims which should only be present in Trust Anchors - // * trust_mark_owners $jws = $this->jsonWebTokenBuilderService->getSignedFederationJwt($builder); @@ -227,6 +241,7 @@ public function fetch(Request $request): Response ], ); + // TODO mivanci Continue // Note: claims which can be present in subordinate statements: // * metadata_policy // * constraints diff --git a/src/Controller/Federation/Test.php b/src/Controller/Federation/Test.php index 443e3f50..64d579cf 100644 --- a/src/Controller/Federation/Test.php +++ b/src/Controller/Federation/Test.php @@ -41,74 +41,86 @@ public function __construct( public function __invoke(): Response { - dd($this->coreFactory->build()); - $t = 'eyJ0eXAiOiJlbnRpdHktc3RhdGVtZW50K2p3dCIsImFsZyI6IlJTMjU2Iiwia2lkIjoiYzRhZmYzY2M3NDM5MWI3M2UxM2FhODE2OTdkYmYzODIifQ.eyJpc3MiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIiLCJpYXQiOjE3MjY4NTM0NTUsImp0aSI6IjQ0ZDQyNDQxOGIyZDEwOWY4M2FhNDMzY2Y0YTVhODNiMTI4YjgzZDZiZDExOTRjMDI1NTgzMTQ1YmZkMjNjMzZjZDg1Y2UzMzBjN2ZlOTc4Iiwic3ViIjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyIiwiZXhwIjoxNzI2OTM5ODU1LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsIm4iOiJzTHpnc0NiaW40Y0l1YUlFZ0w3QzBvaXZSazNyN09HSTBUdWJ0TFBYMkJiMmI5QmtPVElUcnhqSjIwenVVblVLbUJ5eGdyaFJUZGtVWW9EcFJOenVIUENyeVdwU0NQSDB5SUZPUVdxbEFxWHEzXzJheHcwTzlCMFVYVzYzQWNaRVBERVlVWGFsNHNaazE3OG9ZMTNhUlk0Um9NZm8yZkZ1cDlyb2RpSFJqU0gweWsxS2tEOWR5NjZGM1ZmaTF6SHRGQzhkV000clE5cW1OS3pyVFpXMzFsVmQ3N3ZvajZsNE1BOFlYWFVuM2dVMHRocUxMRFI3WnhJcFdUcU1VbzVDRXFJZ0pZS0FRUG5sZldvQ2JiMVhWSl9qMFNQZzZ0M29GNTUwNGd3SFp3M1dDSHJEbUxzdTdpa29CcmdrRWZnS05ISWlra3hXalB0bGNmbmlXUjl2b1EiLCJlIjoiQVFBQiIsImtpZCI6ImM0YWZmM2NjNzQzOTFiNzNlMTNhYTgxNjk3ZGJmMzgyIiwidXNlIjoic2lnIiwiYWxnIjoiUlMyNTYifV19LCJtZXRhZGF0YSI6eyJmZWRlcmF0aW9uX2VudGl0eSI6eyJvcmdhbml6YXRpb25fbmFtZSI6IkZvbyBjb3JwIiwiY29udGFjdHMiOlsiSm9obiBEb2UgamRvZUBleGFtcGxlLm9yZyJdLCJsb2dvX3VyaSI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvbG9nbyIsInBvbGljeV91cmkiOiJodHRwczovL2V4YW1wbGUub3JnL3BvbGljeSIsImhvbWVwYWdlX3VyaSI6Imh0dHBzOi8vZXhhbXBsZS5vcmciLCJmZWRlcmF0aW9uX2ZldGNoX2VuZHBvaW50IjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL2ZlZGVyYXRpb24vZmV0Y2gifSwib3BlbmlkX3Byb3ZpZGVyIjp7Imlzc3VlciI6Imh0dHBzOi8vODItZGFwLmxvY2FsaG9zdC5tYXJrb2l2YW5jaWMuZnJvbS5ociIsImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIvc2ltcGxlc2FtbHBocC9zaW1wbGVzYW1scGhwLTIuMi9tb2R1bGUucGhwL29pZGMvYXV0aG9yaXphdGlvbiIsInRva2VuX2VuZHBvaW50IjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL3Rva2VuIiwidXNlcmluZm9fZW5kcG9pbnQiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIvc2ltcGxlc2FtbHBocC9zaW1wbGVzYW1scGhwLTIuMi9tb2R1bGUucGhwL29pZGMvdXNlcmluZm8iLCJlbmRfc2Vzc2lvbl9lbmRwb2ludCI6Imh0dHBzOi8vODItZGFwLmxvY2FsaG9zdC5tYXJrb2l2YW5jaWMuZnJvbS5oci9zaW1wbGVzYW1scGhwL3NpbXBsZXNhbWxwaHAtMi4yL21vZHVsZS5waHAvb2lkYy9lbmQtc2Vzc2lvbiIsImp3a3NfdXJpIjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL2p3a3MiLCJzY29wZXNfc3VwcG9ydGVkIjpbIm9wZW5pZCIsIm9mZmxpbmVfYWNjZXNzIiwicHJvZmlsZSIsImVtYWlsIiwiYWRkcmVzcyIsInBob25lIiwiaHJFZHVQZXJzb25VbmlxdWVJRCIsInVpZCIsImNuIiwic24iLCJnaXZlbk5hbWUiLCJtYWlsIiwidGVsZXBob25lTnVtYmVyIiwiaHJFZHVQZXJzb25FeHRlbnNpb25OdW1iZXIiLCJtb2JpbGUiLCJmYWNzaW1pbGVUZWxlcGhvbmVOdW1iZXIiLCJockVkdVBlcnNvblVuaXF1ZU51bWJlciIsImhyRWR1UGVyc29uT0lCIiwiaHJFZHVQZXJzb25EYXRlT2ZCaXJ0aCIsImhyRWR1UGVyc29uR2VuZGVyIiwianBlZ1Bob3RvIiwidXNlckNlcnRpZmljYXRlIiwibGFiZWxlZFVSSSIsImhyRWR1UGVyc29uUHJvZmVzc2lvbmFsU3RhdHVzIiwiaHJFZHVQZXJzb25BY2FkZW1pY1N0YXR1cyIsImhyRWR1UGVyc29uU2NpZW5jZUFyZWEiLCJockVkdVBlcnNvbkFmZmlsaWF0aW9uIiwiaHJFZHVQZXJzb25QcmltYXJ5QWZmaWxpYXRpb24iLCJockVkdVBlcnNvblN0dWRlbnRDYXRlZ29yeSIsImhyRWR1UGVyc29uRXhwaXJlRGF0ZSIsImhyRWR1UGVyc29uVGl0bGUiLCJockVkdVBlcnNvblJvbGUiLCJockVkdVBlcnNvblN0YWZmQ2F0ZWdvcnkiLCJockVkdVBlcnNvbkdyb3VwTWVtYmVyIiwibyIsImhyRWR1UGVyc29uSG9tZU9yZyIsIm91Iiwicm9vbU51bWJlciIsInBvc3RhbEFkZHJlc3MiLCJsIiwicG9zdGFsQ29kZSIsInN0cmVldCIsImhvbWVQb3N0YWxBZGRyZXNzIiwiaG9tZVRlbGVwaG9uZU51bWJlciIsImhyRWR1UGVyc29uQ29tbVVSSSIsImhyRWR1UGVyc29uUHJpdmFjeSIsImhyRWR1UGVyc29uUGVyc2lzdGVudElEIiwiZGlzcGxheU5hbWUiLCJzY2hhY1VzZXJQcmVzZW5jZUlEIiwiaHJFZHVQZXJzb25DYXJkTnVtIiwiZm9ybWF0ZWRUZXN0Il0sInJlc3BvbnNlX3R5cGVzX3N1cHBvcnRlZCI6WyJjb2RlIiwidG9rZW4iLCJpZF90b2tlbiIsImlkX3Rva2VuIHRva2VuIl0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInB1YmxpYyJdLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2Il0sImNvZGVfY2hhbGxlbmdlX21ldGhvZHNfc3VwcG9ydGVkIjpbInBsYWluIiwiUzI1NiJdLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbImNsaWVudF9zZWNyZXRfcG9zdCIsImNsaWVudF9zZWNyZXRfYmFzaWMiLCJwcml2YXRlX2tleV9qd3QiXSwicmVxdWVzdF9wYXJhbWV0ZXJfc3VwcG9ydGVkIjp0cnVlLCJyZXF1ZXN0X29iamVjdF9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIm5vbmUiLCJSUzI1NiJdLCJyZXF1ZXN0X3VyaV9wYXJhbWV0ZXJfc3VwcG9ydGVkIjpmYWxzZSwiZ3JhbnRfdHlwZXNfc3VwcG9ydGVkIjpbImF1dGhvcml6YXRpb25fY29kZSIsInJlZnJlc2hfdG9rZW4iXSwiY2xhaW1zX3BhcmFtZXRlcl9zdXBwb3J0ZWQiOnRydWUsImFjcl92YWx1ZXNfc3VwcG9ydGVkIjpbIjEiLCIwIl0sImJhY2tjaGFubmVsX2xvZ291dF9zdXBwb3J0ZWQiOnRydWUsImJhY2tjaGFubmVsX2xvZ291dF9zZXNzaW9uX3N1cHBvcnRlZCI6dHJ1ZSwiY2xpZW50X3JlZ2lzdHJhdGlvbl90eXBlc19zdXBwb3J0ZWQiOlsiYXV0b21hdGljIl0sInJlcXVlc3RfYXV0aGVudGljYXRpb25fbWV0aG9kc19zdXBwb3J0ZWQiOnsiYXV0aG9yaXphdGlvbl9lbmRwb2ludCI6WyJyZXF1ZXN0X29iamVjdCJdfSwicmVxdWVzdF9hdXRoZW50aWNhdGlvbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2Il19fSwiYXV0aG9yaXR5X2hpbnRzIjpbImh0dHBzOi8vZWR1Z2Fpbi5vcmcvIiwiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjLyJdfQ.QOC5hPVzoGe5jJ4o_TkYMyRPWyd7HxqD4flduSAKhF1MIVRkBxgDfV3G1obJd875MsCq_Syb9wZfTP544-nY0z6ulSZm1L08ymzSlWwltcDW-l8rSjuCXErX5UDFNzBwc8ht7F7FfWpNCHrn6-A6t-m5E588IueGZfCqQrKUHRzsObQ8ZCNCkU_hjXgkM-FyERu2_Dnle9wpQ1GszOpNAJAuyMUfissgkokBRrXWwvDbj_7yA8prhgoLhOqtqf_ljMXlx_RggWknd-3zqvBi3U3msHwNnBCQ25E_TH7V_2onASfVOjr2TxyZ5diSkBqoSU9Vqr3bmH3cmcFodu_mvg'; - //$es = $this->federation->entityStatementFetcher()->fromNetwork('https://82-dap.localhost.markoivancic.from.hr/simplesamlphp/simplesamlphp-2.2/module.php/oidc/.well-known/openid-federation'); - $es = $this->federation->entityStatementFetcher()->fromNetwork('https://maiv1.incubator.geant.org/.well-known/openid-federation'); - //dd($es->getPayload(), $es->verifyWithKeySet()); +// dd($this->coreFactory->build()); +// $t = 'eyJ0eXAiOiJlbnRpdHktc3RhdGVtZW50K2p3dCIsImFsZyI6IlJTMjU2Iiwia2lkIjoiYzRhZmYzY2M3NDM5MWI3M2UxM2FhODE2OTdkYmYzODIifQ.eyJpc3MiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIiLCJpYXQiOjE3MjY4NTM0NTUsImp0aSI6IjQ0ZDQyNDQxOGIyZDEwOWY4M2FhNDMzY2Y0YTVhODNiMTI4YjgzZDZiZDExOTRjMDI1NTgzMTQ1YmZkMjNjMzZjZDg1Y2UzMzBjN2ZlOTc4Iiwic3ViIjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyIiwiZXhwIjoxNzI2OTM5ODU1LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IlJTQSIsIm4iOiJzTHpnc0NiaW40Y0l1YUlFZ0w3QzBvaXZSazNyN09HSTBUdWJ0TFBYMkJiMmI5QmtPVElUcnhqSjIwenVVblVLbUJ5eGdyaFJUZGtVWW9EcFJOenVIUENyeVdwU0NQSDB5SUZPUVdxbEFxWHEzXzJheHcwTzlCMFVYVzYzQWNaRVBERVlVWGFsNHNaazE3OG9ZMTNhUlk0Um9NZm8yZkZ1cDlyb2RpSFJqU0gweWsxS2tEOWR5NjZGM1ZmaTF6SHRGQzhkV000clE5cW1OS3pyVFpXMzFsVmQ3N3ZvajZsNE1BOFlYWFVuM2dVMHRocUxMRFI3WnhJcFdUcU1VbzVDRXFJZ0pZS0FRUG5sZldvQ2JiMVhWSl9qMFNQZzZ0M29GNTUwNGd3SFp3M1dDSHJEbUxzdTdpa29CcmdrRWZnS05ISWlra3hXalB0bGNmbmlXUjl2b1EiLCJlIjoiQVFBQiIsImtpZCI6ImM0YWZmM2NjNzQzOTFiNzNlMTNhYTgxNjk3ZGJmMzgyIiwidXNlIjoic2lnIiwiYWxnIjoiUlMyNTYifV19LCJtZXRhZGF0YSI6eyJmZWRlcmF0aW9uX2VudGl0eSI6eyJvcmdhbml6YXRpb25fbmFtZSI6IkZvbyBjb3JwIiwiY29udGFjdHMiOlsiSm9obiBEb2UgamRvZUBleGFtcGxlLm9yZyJdLCJsb2dvX3VyaSI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvbG9nbyIsInBvbGljeV91cmkiOiJodHRwczovL2V4YW1wbGUub3JnL3BvbGljeSIsImhvbWVwYWdlX3VyaSI6Imh0dHBzOi8vZXhhbXBsZS5vcmciLCJmZWRlcmF0aW9uX2ZldGNoX2VuZHBvaW50IjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL2ZlZGVyYXRpb24vZmV0Y2gifSwib3BlbmlkX3Byb3ZpZGVyIjp7Imlzc3VlciI6Imh0dHBzOi8vODItZGFwLmxvY2FsaG9zdC5tYXJrb2l2YW5jaWMuZnJvbS5ociIsImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIvc2ltcGxlc2FtbHBocC9zaW1wbGVzYW1scGhwLTIuMi9tb2R1bGUucGhwL29pZGMvYXV0aG9yaXphdGlvbiIsInRva2VuX2VuZHBvaW50IjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL3Rva2VuIiwidXNlcmluZm9fZW5kcG9pbnQiOiJodHRwczovLzgyLWRhcC5sb2NhbGhvc3QubWFya29pdmFuY2ljLmZyb20uaHIvc2ltcGxlc2FtbHBocC9zaW1wbGVzYW1scGhwLTIuMi9tb2R1bGUucGhwL29pZGMvdXNlcmluZm8iLCJlbmRfc2Vzc2lvbl9lbmRwb2ludCI6Imh0dHBzOi8vODItZGFwLmxvY2FsaG9zdC5tYXJrb2l2YW5jaWMuZnJvbS5oci9zaW1wbGVzYW1scGhwL3NpbXBsZXNhbWxwaHAtMi4yL21vZHVsZS5waHAvb2lkYy9lbmQtc2Vzc2lvbiIsImp3a3NfdXJpIjoiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjL2p3a3MiLCJzY29wZXNfc3VwcG9ydGVkIjpbIm9wZW5pZCIsIm9mZmxpbmVfYWNjZXNzIiwicHJvZmlsZSIsImVtYWlsIiwiYWRkcmVzcyIsInBob25lIiwiaHJFZHVQZXJzb25VbmlxdWVJRCIsInVpZCIsImNuIiwic24iLCJnaXZlbk5hbWUiLCJtYWlsIiwidGVsZXBob25lTnVtYmVyIiwiaHJFZHVQZXJzb25FeHRlbnNpb25OdW1iZXIiLCJtb2JpbGUiLCJmYWNzaW1pbGVUZWxlcGhvbmVOdW1iZXIiLCJockVkdVBlcnNvblVuaXF1ZU51bWJlciIsImhyRWR1UGVyc29uT0lCIiwiaHJFZHVQZXJzb25EYXRlT2ZCaXJ0aCIsImhyRWR1UGVyc29uR2VuZGVyIiwianBlZ1Bob3RvIiwidXNlckNlcnRpZmljYXRlIiwibGFiZWxlZFVSSSIsImhyRWR1UGVyc29uUHJvZmVzc2lvbmFsU3RhdHVzIiwiaHJFZHVQZXJzb25BY2FkZW1pY1N0YXR1cyIsImhyRWR1UGVyc29uU2NpZW5jZUFyZWEiLCJockVkdVBlcnNvbkFmZmlsaWF0aW9uIiwiaHJFZHVQZXJzb25QcmltYXJ5QWZmaWxpYXRpb24iLCJockVkdVBlcnNvblN0dWRlbnRDYXRlZ29yeSIsImhyRWR1UGVyc29uRXhwaXJlRGF0ZSIsImhyRWR1UGVyc29uVGl0bGUiLCJockVkdVBlcnNvblJvbGUiLCJockVkdVBlcnNvblN0YWZmQ2F0ZWdvcnkiLCJockVkdVBlcnNvbkdyb3VwTWVtYmVyIiwibyIsImhyRWR1UGVyc29uSG9tZU9yZyIsIm91Iiwicm9vbU51bWJlciIsInBvc3RhbEFkZHJlc3MiLCJsIiwicG9zdGFsQ29kZSIsInN0cmVldCIsImhvbWVQb3N0YWxBZGRyZXNzIiwiaG9tZVRlbGVwaG9uZU51bWJlciIsImhyRWR1UGVyc29uQ29tbVVSSSIsImhyRWR1UGVyc29uUHJpdmFjeSIsImhyRWR1UGVyc29uUGVyc2lzdGVudElEIiwiZGlzcGxheU5hbWUiLCJzY2hhY1VzZXJQcmVzZW5jZUlEIiwiaHJFZHVQZXJzb25DYXJkTnVtIiwiZm9ybWF0ZWRUZXN0Il0sInJlc3BvbnNlX3R5cGVzX3N1cHBvcnRlZCI6WyJjb2RlIiwidG9rZW4iLCJpZF90b2tlbiIsImlkX3Rva2VuIHRva2VuIl0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInB1YmxpYyJdLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2Il0sImNvZGVfY2hhbGxlbmdlX21ldGhvZHNfc3VwcG9ydGVkIjpbInBsYWluIiwiUzI1NiJdLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbImNsaWVudF9zZWNyZXRfcG9zdCIsImNsaWVudF9zZWNyZXRfYmFzaWMiLCJwcml2YXRlX2tleV9qd3QiXSwicmVxdWVzdF9wYXJhbWV0ZXJfc3VwcG9ydGVkIjp0cnVlLCJyZXF1ZXN0X29iamVjdF9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIm5vbmUiLCJSUzI1NiJdLCJyZXF1ZXN0X3VyaV9wYXJhbWV0ZXJfc3VwcG9ydGVkIjpmYWxzZSwiZ3JhbnRfdHlwZXNfc3VwcG9ydGVkIjpbImF1dGhvcml6YXRpb25fY29kZSIsInJlZnJlc2hfdG9rZW4iXSwiY2xhaW1zX3BhcmFtZXRlcl9zdXBwb3J0ZWQiOnRydWUsImFjcl92YWx1ZXNfc3VwcG9ydGVkIjpbIjEiLCIwIl0sImJhY2tjaGFubmVsX2xvZ291dF9zdXBwb3J0ZWQiOnRydWUsImJhY2tjaGFubmVsX2xvZ291dF9zZXNzaW9uX3N1cHBvcnRlZCI6dHJ1ZSwiY2xpZW50X3JlZ2lzdHJhdGlvbl90eXBlc19zdXBwb3J0ZWQiOlsiYXV0b21hdGljIl0sInJlcXVlc3RfYXV0aGVudGljYXRpb25fbWV0aG9kc19zdXBwb3J0ZWQiOnsiYXV0aG9yaXphdGlvbl9lbmRwb2ludCI6WyJyZXF1ZXN0X29iamVjdCJdfSwicmVxdWVzdF9hdXRoZW50aWNhdGlvbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2Il19fSwiYXV0aG9yaXR5X2hpbnRzIjpbImh0dHBzOi8vZWR1Z2Fpbi5vcmcvIiwiaHR0cHM6Ly84Mi1kYXAubG9jYWxob3N0Lm1hcmtvaXZhbmNpYy5mcm9tLmhyL3NpbXBsZXNhbWxwaHAvc2ltcGxlc2FtbHBocC0yLjIvbW9kdWxlLnBocC9vaWRjLyJdfQ.QOC5hPVzoGe5jJ4o_TkYMyRPWyd7HxqD4flduSAKhF1MIVRkBxgDfV3G1obJd875MsCq_Syb9wZfTP544-nY0z6ulSZm1L08ymzSlWwltcDW-l8rSjuCXErX5UDFNzBwc8ht7F7FfWpNCHrn6-A6t-m5E588IueGZfCqQrKUHRzsObQ8ZCNCkU_hjXgkM-FyERu2_Dnle9wpQ1GszOpNAJAuyMUfissgkokBRrXWwvDbj_7yA8prhgoLhOqtqf_ljMXlx_RggWknd-3zqvBi3U3msHwNnBCQ25E_TH7V_2onASfVOjr2TxyZ5diSkBqoSU9Vqr3bmH3cmcFodu_mvg'; +// $es = $this->federation->entityStatementFetcher()->fromNetwork('https://82-dap.localhost.markoivancic.from.hr/simplesamlphp/simplesamlphp-2.2/module.php/oidc/.well-known/openid-federation'); +// $es = $this->federation->entityStatementFetcher()->fromNetwork('https://maiv1.incubator.geant.org/.well-known/openid-federation'); +// dd($es->getPayload(), $es->verifyWithKeySet()); - $this->federationCache->cache->clear(); +// $this->federationCache->cache->clear(); //$this->protocolCache->set('value', 10, 'test'); //dd($this->protocolCache, $this->protocolCache->get(null, 'test')); - $requestObjectFactory = (new Core())->requestObjectFactory(); +// $requestObjectFactory = (new Core())->requestObjectFactory(); // {"alg":"none"}, {"iss":"joe", // "exp":1300819380, // "http://example.com/is_root":true} - $unprotectedJws = 'eyJhbGciOiJub25lIn0.' . - 'eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'; +// $unprotectedJws = 'eyJhbGciOiJub25lIn0.' . +// 'eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'; - $requestObject = $requestObjectFactory->fromToken($unprotectedJws); +// $requestObject = $requestObjectFactory->fromToken($unprotectedJws); // dd($requestObject, $requestObject->getPayload(), $requestObject->getHeader()); // $cache->clear(); $trustChain = $this->federation ->trustChainResolver() -// ->for( -// 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ALeaf/', -// [ -// 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ABTrustAnchor/', -// 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/CTrustAnchor/', -// ], -// ); ->for( + '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://maiv1.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/', ], ); $leaf = $trustChain->getResolvedLeaf(); - +// dd($leaf); $leafFederationJwks = $leaf->getJwks(); - - /** @psalm-suppress PossiblyNullArgument */ +// dd($leafFederationJwks); +// /** @psalm-suppress PossiblyNullArgument */ $resolvedMetadata = $trustChain->getResolvedMetadata(EntityTypesEnum::OpenIdRelyingParty); $clientEntity = $this->clientEntityFactory->fromRegistrationData( $resolvedMetadata, RegistrationTypeEnum::FederatedAutomatic, ); - dd($resolvedMetadata, $clientEntity); +// dd($resolvedMetadata, $clientEntity); $jwksUri = $resolvedMetadata['jwks_uri'] ?? null; $signedJwksUri = $resolvedMetadata['signed_jwks_uri'] ?? null; // dd($leaf, $leafFederationJwks, $resolvedMetadata, $jwksUri, $signedJwksUri); - $cachedJwks = $jwksUri ? $this->jwks->jwksFetcher()->fromCache($jwksUri) : null; - $jwks = $jwksUri ? $this->jwks->jwksFetcher()->fromJwksUri($jwksUri) : null; +// $cachedJwks = $jwksUri ? $this->jwks->jwksFetcher()->fromCache($jwksUri) : null; +// $jwks = $jwksUri ? $this->jwks->jwksFetcher()->fromJwksUri($jwksUri) : null; - $cachedSignedJwks = $signedJwksUri ? $this->jwks->jwksFetcher()->fromCache($signedJwksUri) : null; +//$leafFederationJwks = [ +// 'keys' => +// [ +// 0 => +// [ +// 'alg' => 'RS256', +// 'use' => 'sig', +// 'kty' => 'RSA', +// 'n' => 'pJgG9F_lwc2cFEC1l6q0fjJYxKPbtVGqJpDggDpDR8MgfbH0jUZP_RvhJGpl_09Bp-PfibLiwxchHZlrCx-fHQyGMaBRivUfq_p12ECEXMaFUcasCP6cyNrDfa5Uchumau4WeC21nYI1NMawiMiWFcHpLCQ7Ul8NMaCM_dkeruhm_xG0ZCqfwu30jOyCsnZdE0izJwPTfBRLpLyivu8eHpwjoIzmwqo8H-ZsbqR0vdRu20-MNS78ppTxwK3QmJhU6VO2r730F6WH9xJd_XUDuVeM4_6Z6WVDXw3kQF-jlpfcssPP303nbqVmfFZSUgS8buToErpMqevMIKREShsjMQ', +// 'e' => 'AQAB', +// 'kid' => 'F4VFObNusj3PHmrHxpqh4GNiuFHlfh-2s6xMJ95fLYA', +// ], +// ], +//]; +// $signedJwksUri = 'https://08-dap.localhost.markoivancic.from.hr/openid/entities/ALeaf/signed-jwks'; $signedJwks = $signedJwksUri ? $this->jwks->jwksFetcher() ->fromSignedJwksUri($signedJwksUri, $leafFederationJwks) : null; - dd( - $signedJwksUri, - $cachedSignedJwks, - $signedJwks, - ); + $cachedSignedJwks = $signedJwksUri ? $this->jwks->jwksFetcher()->fromCache($signedJwksUri) : null; + dd($signedJwksUri, $cachedSignedJwks, $signedJwks); +// dd( +// $signedJwksUri, +// $cachedSignedJwks, +// $signedJwks, +// ); return new JsonResponse( $trustChain->getResolvedMetadata(EntityTypesEnum::OpenIdRelyingParty), diff --git a/src/ModuleConfig.php b/src/ModuleConfig.php index ff4b7429..eec9669c 100644 --- a/src/ModuleConfig.php +++ b/src/ModuleConfig.php @@ -76,6 +76,7 @@ class ModuleConfig final public const OPTION_FEDERATION_CACHE_ADAPTER_ARGUMENTS = 'federation_cache_adapter_arguments'; final public const OPTION_FEDERATION_CACHE_MAX_DURATION = 'federation_cache_max_duration'; final public const OPTION_FEDERATION_TRUST_ANCHORS = 'federation_trust_anchors'; + final public const OPTION_FEDERATION_TRUST_MARK_TOKENS = 'federation_trust_mark_tokens'; final public const OPTION_FEDERATION_ENTITY_STATEMENT_CACHE_DURATION = 'federation_entity_statement_cache_duration'; final public const OPTION_PROTOCOL_CACHE_ADAPTER = 'protocol_cache_adapter'; final public const OPTION_PROTOCOL_CACHE_ADAPTER_ARGUMENTS = 'protocol_cache_adapter_arguments'; @@ -478,6 +479,16 @@ public function getFederationAuthorityHints(): ?array return empty($authorityHints) ? null : $authorityHints; } + public function getFederationTrustMarkTokens(): ?array + { + $trustMarks = $this->config()->getOptionalArray( + self::OPTION_FEDERATION_TRUST_MARK_TOKENS, + null, + ); + + return empty($trustMarks) ? null : $trustMarks; + } + public function getOrganizationName(): ?string { return $this->config()->getOptionalString( diff --git a/src/Server/Exceptions/OidcServerException.php b/src/Server/Exceptions/OidcServerException.php index 8a88f0bf..695b5e69 100644 --- a/src/Server/Exceptions/OidcServerException.php +++ b/src/Server/Exceptions/OidcServerException.php @@ -253,7 +253,7 @@ public static function invalidTrustChain( ): OidcServerException { $errorMessage = 'Trust chain validation failed.'; - $e = new self($errorMessage, 12, 'validation_failed', 400, $hint, $redirectUri, $previous, $state); + $e = new self($errorMessage, 12, 'trust_chain_validation_failed', 400, $hint, $redirectUri, $previous, $state); $e->useFragmentInHttpResponses($useFragment); return $e; diff --git a/src/Services/OpMetadataService.php b/src/Services/OpMetadataService.php index e869a2c2..096cfbaf 100644 --- a/src/Services/OpMetadataService.php +++ b/src/Services/OpMetadataService.php @@ -59,6 +59,9 @@ private function initMetadata(): void TokenEndpointAuthMethodsEnum::ClientSecretBasic->value, TokenEndpointAuthMethodsEnum::PrivateKeyJwt->value, ]; + $this->metadata[ClaimsEnum::TokenEndpointAuthSigningAlgValuesSupported->value] = [ + $signer->algorithmId(), + ]; $this->metadata[ClaimsEnum::RequestParameterSupported->value] = true; $this->metadata[ClaimsEnum::RequestObjectSigningAlgValuesSupported->value] = [ 'none', diff --git a/tests/unit/src/Services/OpMetadataServiceTest.php b/tests/unit/src/Services/OpMetadataServiceTest.php index 3dbb3f5e..3a6c1f16 100644 --- a/tests/unit/src/Services/OpMetadataServiceTest.php +++ b/tests/unit/src/Services/OpMetadataServiceTest.php @@ -90,6 +90,9 @@ public function testItReturnsExpectedMetadata(): void 'client_secret_basic', 'private_key_jwt', ], + 'token_endpoint_auth_signing_alg_values_supported' => [ + 'RS256', + ], 'request_parameter_supported' => true, 'request_object_signing_alg_values_supported' => ['none', 'RS256'], 'request_uri_parameter_supported' => false,