Skip to content

Commit 847111a

Browse files
committed
Pre auth code release modification
1 parent ce40d95 commit 847111a

22 files changed

+532
-104
lines changed

config/module_oidc.php.dist

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,25 @@ $config = [
510510
// Enable or disable verifiable credentials capabilities. Default is disabled (false).
511511
ModuleConfig::OPTION_VERIFIABLE_CREDENTIAL_ENABLED => false,
512512

513+
// Allow or disallow non-registered clients to request verifiable credentials. Default is disallowed (false).
514+
ModuleConfig::OPTION_ALLOW_NON_REGISTERED_CLIENTS_FOR_VCI => false,
515+
516+
// Allowed redirect URI prefixes for non-registered clients. By default, this is set to
517+
// 'openid-credential-offer://' to allow only redirect URIs with this prefix.
518+
//
519+
// Example:
520+
// [
521+
// 'https://example.org/redirect',
522+
// 'https://example.org/redirect2',
523+
// ]
524+
//
525+
ModuleConfig::OPTION_ALLOWED_REDIRECT_URI_PREFIXES_FOR_NON_REGISTERED_CLIENTS_FOR_VCI => [
526+
'openid-credential-offer://',
527+
],
528+
529+
// Allow or disallow clients to request verifiable credentials using Authorization Code Grant without client ID.
530+
// Default is disallowed (false).
531+
ModuleConfig::OPTION_ALLOW_VCI_AUTHORIZATION_CODE_REQUESTS_WITHOUT_CLIENT_ID => false,
513532

514533
// (optional) Credential configuration statements, as per `credential_configurations_supported` claim definition in
515534
// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#credential-issuer-parameters.
@@ -813,11 +832,8 @@ $config = [
813832
// (optional) Enable or disable API capabilities. Default is disabled (false).
814833
ModuleConfig::OPTION_API_ENABLED => false,
815834

816-
/**
817-
* List of API tokens which can be used to access API endpoints based on given scopes.
818-
*
819-
* The format is: ['token' => [ApiScopesEnum]]
820-
*/
835+
// List of API tokens which can be used to access API endpoints based on given scopes.
836+
// The format is: ['token' => [ApiScopesEnum]]
821837
ModuleConfig::OPTION_API_TOKENS => [
822838
// 'strong-random-token-string' => [
823839
// \SimpleSAML\Module\oidc\Codebooks\ApiScopesEnum::All, // Gives access to the whole API.

src/Factories/AuthSimpleFactory.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
namespace SimpleSAML\Module\oidc\Factories;
1818

19+
use League\OAuth2\Server\Entities\ClientEntityInterface as OAuth2ClientEntityInterface;
1920
use SimpleSAML\Auth\Simple;
2021
use SimpleSAML\Module\oidc\Entities\Interfaces\ClientEntityInterface;
2122
use SimpleSAML\Module\oidc\ModuleConfig;
@@ -31,7 +32,7 @@ public function __construct(
3132
* @codeCoverageIgnore
3233
* @throws \Exception
3334
*/
34-
public function build(ClientEntityInterface $clientEntity): Simple
35+
public function build(OAuth2ClientEntityInterface $clientEntity): Simple
3536
{
3637
$authSourceId = $this->resolveAuthSourceId($clientEntity);
3738

@@ -52,9 +53,15 @@ public function getDefaultAuthSource(): Simple
5253
*
5354
* @throws \Exception
5455
*/
55-
public function resolveAuthSourceId(ClientEntityInterface $client): string
56+
public function resolveAuthSourceId(OAuth2ClientEntityInterface $client): string
5657
{
57-
return $client->getAuthSourceId() ?? $this->moduleConfig->getDefaultAuthSourceId();
58+
$defaultAuthSourceId = $this->moduleConfig->getDefaultAuthSourceId();
59+
60+
if ($client instanceof ClientEntityInterface) {
61+
$client->getAuthSourceId() ?? $this->moduleConfig->getDefaultAuthSourceId();
62+
}
63+
64+
return $defaultAuthSourceId;
5865
}
5966

6067
public function forAuthSourceId(string $authSourceId): Simple

src/Factories/CredentialOfferUriFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public function buildPreAuthorized(
132132

133133
// Currently, we need a dedicated client for which the PreAuthZed code will be bound to.
134134
// TODO mivanci: Remove requirement for dedicated client for (pre-)authorization codes.
135-
$client = $this->clientEntityFactory->getGenericForVciPreAuthZFlow();
135+
$client = $this->clientEntityFactory->getGenericForVci();
136136
if ($this->clientRepository->findById($client->getIdentifier()) === null) {
137137
$this->clientRepository->add($client);
138138
} else {

src/Factories/Entities/ClientEntityFactory.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ public function fromState(array $state): ClientEntityInterface
383383
);
384384
}
385385

386-
public function getGenericForVciPreAuthZFlow(): ClientEntityInterface
386+
public function getGenericForVci(): ClientEntityInterface
387387
{
388388
$clientId = 'vci_' .
389389
hash('sha256', 'vci_' . $this->moduleConfig->sspConfig()->getString('secretsalt'));
@@ -397,8 +397,8 @@ public function getGenericForVciPreAuthZFlow(): ClientEntityInterface
397397
return $this->fromData(
398398
id: $clientId,
399399
secret: $clientSecret,
400-
name: 'VCI Pre-authorized Code Generic Client',
401-
description: 'Generic client for VCI Pre-authorized Code',
400+
name: 'VCI Generic Client',
401+
description: 'Generic client for Verifiable Credential Issuance flows.',
402402
redirectUri: ['openid-credential-offer://'],
403403
scopes: ['openid', ...$credentialConfigurationIdsSupported],
404404
isEnabled: true,

src/Factories/RequestRulesManagerFactory.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use SimpleSAML\Module\oidc\ModuleConfig;
1111
use SimpleSAML\Module\oidc\Repositories\ClientRepository;
1212
use SimpleSAML\Module\oidc\Repositories\CodeChallengeVerifiersRepository;
13+
use SimpleSAML\Module\oidc\Repositories\IssuerStateRepository;
1314
use SimpleSAML\Module\oidc\Repositories\ScopeRepository;
1415
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
1516
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AcrValuesRule;
@@ -20,6 +21,7 @@
2021
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeChallengeRule;
2122
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeVerifierRule;
2223
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\IdTokenHintRule;
24+
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\IssuerStateRule;
2325
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\MaxAgeRule;
2426
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\PostLogoutRedirectUriRule;
2527
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\PromptRule;
@@ -62,6 +64,7 @@ public function __construct(
6264
private readonly JwksResolver $jwksResolver,
6365
private readonly FederationParticipationValidator $federationParticipationValidator,
6466
private readonly SspBridge $sspBridge,
67+
private readonly IssuerStateRepository $issuerStateRepository,
6568
private readonly ?FederationCache $federationCache = null,
6669
private readonly ?ProtocolCache $protocolCache = null,
6770
) {
@@ -93,9 +96,10 @@ private function getDefaultRules(): array
9396
$this->federation,
9497
$this->jwksResolver,
9598
$this->federationParticipationValidator,
99+
$this->logger,
96100
$this->federationCache,
97101
),
98-
new RedirectUriRule($this->requestParamsResolver, $this->helpers),
102+
new RedirectUriRule($this->requestParamsResolver, $this->helpers, $this->moduleConfig),
99103
new RequestObjectRule($this->requestParamsResolver, $this->helpers, $this->jwksResolver),
100104
new PromptRule(
101105
$this->requestParamsResolver,
@@ -141,6 +145,7 @@ private function getDefaultRules(): array
141145
$this->protocolCache,
142146
),
143147
new CodeVerifierRule($this->requestParamsResolver, $this->helpers),
148+
new IssuerStateRule($this->requestParamsResolver, $this->helpers, $this->issuerStateRepository),
144149
];
145150
}
146151
}

src/ModuleConfig.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ class ModuleConfig
109109
final public const OPTION_AUTH_SOURCES_TO_USERS_EMAIL_ATTRIBUTE_NAME_MAP =
110110
'auth_sources_to_users_email_attribute_name_map';
111111
final public const OPTION_ISSUER_STATE_TTL = 'issuer_state_ttl';
112+
final public const OPTION_ALLOW_NON_REGISTERED_CLIENTS_FOR_VCI = 'allow_non_registered_clients_for_vci';
113+
final public const OPTION_ALLOW_VCI_AUTHORIZATION_CODE_REQUESTS_WITHOUT_CLIENT_ID =
114+
'allow_vci_authorization_code_requests_without_client_id';
115+
final public const OPTION_ALLOWED_REDIRECT_URI_PREFIXES_FOR_NON_REGISTERED_CLIENTS_FOR_VCI =
116+
'allowed_redirect_uri_prefixes_for_non_registered_clients_for_vci';
112117

113118
protected static array $standardScopes = [
114119
ScopesEnum::OpenId->value => [
@@ -1048,4 +1053,25 @@ public function getIssuerStateDuration(): DateInterval
10481053
$this->config()->getString(self::OPTION_ISSUER_STATE_TTL),
10491054
);
10501055
}
1056+
1057+
public function getAllowNonRegisteredClientsForVci(): bool
1058+
{
1059+
return $this->config()->getOptionalBoolean(self::OPTION_ALLOW_NON_REGISTERED_CLIENTS_FOR_VCI, false);
1060+
}
1061+
1062+
public function getAllowVciAuthorizationCodeRequestsWithoutClientId(): bool
1063+
{
1064+
return $this->config()->getOptionalBoolean(
1065+
self::OPTION_ALLOW_VCI_AUTHORIZATION_CODE_REQUESTS_WITHOUT_CLIENT_ID,
1066+
false,
1067+
);
1068+
}
1069+
1070+
public function getAllowedRedirectUriPrefixesForNonRegisteredClientsForVci(): array
1071+
{
1072+
return $this->config()->getOptionalArray(
1073+
self::OPTION_ALLOWED_REDIRECT_URI_PREFIXES_FOR_NON_REGISTERED_CLIENTS_FOR_VCI,
1074+
['openid-credential-offer://',],
1075+
);
1076+
}
10511077
}

src/Server/Grants/AuthCodeGrant.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeChallengeMethodRule;
4545
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeChallengeRule;
4646
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeVerifierRule;
47+
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\IssuerStateRule;
4748
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\MaxAgeRule;
4849
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\PromptRule;
4950
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\RedirectUriRule;
@@ -658,6 +659,7 @@ public function validateAuthorizationRequestWithRequestRules(
658659
RequiredOpenIdScopeRule::class,
659660
CodeChallengeRule::class,
660661
CodeChallengeMethodRule::class,
662+
IssuerStateRule::class,
661663
];
662664

663665
// Since we have already validated redirect_uri, and we have state, make it available for other checkers.
@@ -738,6 +740,17 @@ public function validateAuthorizationRequestWithRequestRules(
738740
$acrValues = $resultBag->getOrFail(AcrValuesRule::class)->getValue();
739741
$authorizationRequest->setRequestedAcrValues($acrValues);
740742

743+
$authorizationRequest->setIsVciRequest(
744+
$this->requestParamsResolver->isVciAuthorizationCodeRequest(
745+
$request,
746+
$this->allowedAuthorizationHttpMethods,
747+
),
748+
);
749+
750+
/** @var ?string $issuerState */
751+
$issuerState = $resultBag->get(IssuerStateRule::class)?->getValue();
752+
$authorizationRequest->setIssuerState($issuerState);
753+
741754
return $authorizationRequest;
742755
}
743756

src/Server/Grants/PreAuthCodeGrant.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function respondToAccessTokenRequest(
124124
);
125125

126126
if (empty($preAuthorizedCodeId)) {
127-
$this->loggerService->warning('Empty pre-authorized code ID.');
127+
$this->loggerService->error('Empty pre-authorized code ID.');
128128
throw OidcServerException::invalidRequest(ParamsEnum::PreAuthorizedCode->value);
129129
}
130130

@@ -142,6 +142,13 @@ public function respondToAccessTokenRequest(
142142
throw OidcServerException::invalidGrant('Invalid pre-authorized code.');
143143
}
144144

145+
if (!$preAuthorizedCode->isPreAuthorized()) {
146+
$this->loggerService->error(
147+
'Pre-authorized code is not pre-authorized. Value was: ' . $preAuthorizedCodeId,
148+
);
149+
throw OidcServerException::invalidGrant('Pre-authorized code is not pre-authorized.');
150+
}
151+
145152
if ($preAuthorizedCode->isRevoked()) {
146153
$this->loggerService->error('Pre-authorized code is revoked. Value was: ' . $preAuthorizedCodeId);
147154
throw OidcServerException::invalidGrant('Pre-authorized code is revoked.');

0 commit comments

Comments
 (0)