Skip to content

Commit 14317dd

Browse files
committed
Introduce auth code flow type attribute
1 parent 847111a commit 14317dd

File tree

10 files changed

+69
-24
lines changed

10 files changed

+69
-24
lines changed

docker/conformance.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ CREATE TABLE oidc_auth_code (
8282
client_id VARCHAR(191) NOT NULL,
8383
is_revoked BOOLEAN NOT NULL DEFAULT false,
8484
redirect_uri TEXT NOT NULL, nonce TEXT NULL,
85-
is_pre_authorized BOOLEAN NOT NULL DEFAULT false,
85+
flow_type CHAR(64) DEFAULT NULL,
8686
tx_code varchar(191) DEFAULT NULL,
8787
CONSTRAINT FK_97D32CA7A76ED395 FOREIGN KEY (user_id)
8888
REFERENCES oidc_user (id) ON DELETE CASCADE,

src/Codebooks/FlowTypeEnum.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Module\oidc\Codebooks;
6+
7+
enum FlowTypeEnum: string
8+
{
9+
case OidcAuthorizationCode = 'oidc_authorization_code';
10+
case OidcImplicit = 'oidc_implicit';
11+
case OidcHybrid = 'oidc_hybrid';
12+
case OidcRefreshToken = 'oidc_refresh_token';
13+
14+
case VciAuthorizationCode = 'vci_authorization_code';
15+
case VciPreAuthorizedCode = 'vci_pre_authorized_code';
16+
}

src/Entities/AuthCodeEntity.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use League\OAuth2\Server\Entities\ClientEntityInterface as OAuth2ClientEntityInterface;
2020
use League\OAuth2\Server\Entities\Traits\EntityTrait;
2121
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
22+
use SimpleSAML\Module\oidc\Codebooks\FlowTypeEnum;
2223
use SimpleSAML\Module\oidc\Entities\Interfaces\AuthCodeEntityInterface;
2324
use SimpleSAML\Module\oidc\Entities\Interfaces\MementoInterface;
2425
use SimpleSAML\Module\oidc\Entities\Traits\OidcAuthCodeTrait;
@@ -43,7 +44,7 @@ public function __construct(
4344
?string $redirectUri = null,
4445
?string $nonce = null,
4546
bool $isRevoked = false,
46-
protected readonly bool $isPreAuthorized = false,
47+
protected readonly ?FlowTypeEnum $flowTypeEnum = null,
4748
protected readonly ?string $txCode = null,
4849
) {
4950
$this->identifier = $id;
@@ -70,18 +71,23 @@ public function getState(): array
7071
'is_revoked' => $this->isRevoked(),
7172
'redirect_uri' => $this->getRedirectUri(),
7273
'nonce' => $this->getNonce(),
73-
'is_pre_authorized' => $this->isPreAuthorized,
74+
'flow_type' => $this->flowTypeEnum?->value,
7475
'tx_code' => $this->txCode,
7576
];
7677
}
7778

78-
public function isPreAuthorized(): bool
79+
public function isVciPreAuthorized(): bool
7980
{
80-
return $this->isPreAuthorized;
81+
return $this->flowTypeEnum === FlowTypeEnum::VciPreAuthorizedCode;
8182
}
8283

8384
public function getTxCode(): ?string
8485
{
8586
return $this->txCode;
8687
}
88+
89+
public function getFlowTypeEnum(): ?FlowTypeEnum
90+
{
91+
return $this->flowTypeEnum;
92+
}
8793
}

src/Factories/CredentialOfferUriFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use RuntimeException;
99
use SimpleSAML\Error\Exception;
1010
use SimpleSAML\Module\oidc\Bridges\SspBridge;
11+
use SimpleSAML\Module\oidc\Codebooks\FlowTypeEnum;
1112
use SimpleSAML\Module\oidc\Codebooks\ParametersEnum;
1213
use SimpleSAML\Module\oidc\Entities\ScopeEntity;
1314
use SimpleSAML\Module\oidc\Entities\UserEntity;
@@ -202,7 +203,7 @@ public function buildPreAuthorized(
202203
expiryDateTime: (new DateTimeImmutable())->add($this->moduleConfig->getAuthCodeDuration()),
203204
userIdentifier: $userId,
204205
redirectUri: 'openid-credential-offer://',
205-
isPreAuthorized: true,
206+
flowTypeEnum: FlowTypeEnum::VciPreAuthorizedCode,
206207
txCode: $txCode instanceof VerifiableCredentials\TxCode ? $txCode->getCodeAsString() : null,
207208
);
208209
$this->authCodeRepository->persistNewAuthCode($authCode);

src/Factories/Entities/AuthCodeEntityFactory.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DateTimeImmutable;
88
use League\OAuth2\Server\Entities\ClientEntityInterface as OAuth2ClientEntityInterface;
9+
use SimpleSAML\Module\oidc\Codebooks\FlowTypeEnum;
910
use SimpleSAML\Module\oidc\Entities\AuthCodeEntity;
1011
use SimpleSAML\Module\oidc\Entities\Interfaces\ClientEntityInterface;
1112
use SimpleSAML\Module\oidc\Helpers;
@@ -31,7 +32,7 @@ public function fromData(
3132
?string $redirectUri = null,
3233
?string $nonce = null,
3334
bool $isRevoked = false,
34-
bool $isPreAuthorized = false,
35+
?FlowTypeEnum $flowTypeEnum = null,
3536
?string $txCode = null,
3637
): AuthCodeEntity {
3738
return new AuthCodeEntity(
@@ -43,7 +44,7 @@ public function fromData(
4344
$redirectUri,
4445
$nonce,
4546
$isRevoked,
46-
$isPreAuthorized,
47+
$flowTypeEnum,
4748
$txCode,
4849
);
4950
}
@@ -85,7 +86,7 @@ public function fromState(array $state): AuthCodeEntity
8586
$redirectUri = empty($state['redirect_uri']) ? null : (string)$state['redirect_uri'];
8687
$nonce = empty($state['nonce']) ? null : (string)$state['nonce'];
8788
$isRevoked = (bool) $state['is_revoked'];
88-
$isPreAuthorized = (bool) $state['is_pre_authorized'];
89+
$flowType = empty($state['flow_type']) ? null : FlowTypeEnum::tryFrom((string)$state['flow_type']);
8990
$txCode = empty($state['tx_code']) ? null : (string)$state['tx_code'];
9091

9192
return $this->fromData(
@@ -97,7 +98,7 @@ public function fromState(array $state): AuthCodeEntity
9798
$redirectUri,
9899
$nonce,
99100
$isRevoked,
100-
$isPreAuthorized,
101+
$flowType,
101102
$txCode,
102103
);
103104
}

src/Repositories/AuthCodeRepository.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function persistNewAuthCode(OAuth2AuthCodeEntityInterface $authCodeEntity
8080
is_revoked,
8181
redirect_uri,
8282
nonce,
83-
is_pre_authorized,
83+
flow_type,
8484
tx_code
8585
) VALUES (
8686
:id,
@@ -91,7 +91,7 @@ public function persistNewAuthCode(OAuth2AuthCodeEntityInterface $authCodeEntity
9191
:is_revoked,
9292
:redirect_uri,
9393
:nonce,
94-
:is_pre_authorized,
94+
:flow_type,
9595
:tx_code
9696
)
9797
EOS,
@@ -214,7 +214,7 @@ private function update(AuthCodeEntity $authCodeEntity): void
214214
is_revoked = :is_revoked,
215215
redirect_uri = :redirect_uri,
216216
nonce = :nonce,
217-
is_pre_authorized = :is_pre_authorized,
217+
flow_type = :flow_type,
218218
tx_code = :tx_code
219219
WHERE id = :id
220220
EOS
@@ -239,10 +239,8 @@ private function update(AuthCodeEntity $authCodeEntity): void
239239
protected function preparePdoState(array $state): array
240240
{
241241
$isRevoked = (bool)($state['is_revoked'] ?? true);
242-
$isPreAuthorized = (bool)($state['is_pre_authorized'] ?? false);
243242

244243
$state['is_revoked'] = [$isRevoked, PDO::PARAM_BOOL];
245-
$state['is_pre_authorized'] = [$isPreAuthorized, PDO::PARAM_BOOL];
246244

247245
return $state;
248246
}

src/Server/Grants/AuthCodeGrant.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
2222
use LogicException;
2323
use Psr\Http\Message\ServerRequestInterface;
24+
use SimpleSAML\Module\oidc\Codebooks\FlowTypeEnum;
2425
use SimpleSAML\Module\oidc\Entities\Interfaces\AccessTokenEntityInterface;
2526
use SimpleSAML\Module\oidc\Entities\Interfaces\AuthCodeEntityInterface;
2627
use SimpleSAML\Module\oidc\Entities\Interfaces\RefreshTokenEntityInterface;
@@ -270,8 +271,7 @@ public function completeOidcAuthorizationRequest(
270271
$authorizationRequest->getClient(),
271272
$user->getIdentifier(),
272273
$finalRedirectUri,
273-
$authorizationRequest->getScopes(),
274-
$authorizationRequest->getNonce(),
274+
$authorizationRequest,
275275
);
276276

277277
$payload = [
@@ -307,7 +307,6 @@ public function completeOidcAuthorizationRequest(
307307
}
308308

309309
/**
310-
* @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes
311310
* @throws \League\OAuth2\Server\Exception\OAuthServerException
312311
* @throws \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
313312
*/
@@ -316,25 +315,29 @@ protected function issueOidcAuthCode(
316315
OAuth2ClientEntityInterface $client,
317316
string $userIdentifier,
318317
string $redirectUri,
319-
array $scopes = [],
320-
?string $nonce = null,
318+
AuthorizationRequest $authorizationRequest,
321319
): AuthCodeEntityInterface {
322320
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
323321

324322
if (!is_a($this->authCodeRepository, AuthCodeRepositoryInterface::class)) {
325323
throw OidcServerException::serverError('Unexpected auth code repository entity type.');
326324
}
327325

326+
$flowType = $authorizationRequest->isVciRequest() ?
327+
FlowTypeEnum::VciAuthorizationCode :
328+
FlowTypeEnum::OidcAuthorizationCode;
329+
328330
while ($maxGenerationAttempts-- > 0) {
329331
try {
330332
$authCode = $this->authCodeEntityFactory->fromData(
331333
$this->generateUniqueIdentifier(),
332334
$client,
333-
$scopes,
335+
$authorizationRequest->getScopes(),
334336
(new DateTimeImmutable())->add($authCodeTTL),
335337
$userIdentifier,
336338
$redirectUri,
337-
$nonce,
339+
$authorizationRequest->getNonce(),
340+
flowTypeEnum: $flowType,
338341
);
339342
$this->authCodeRepository->persistNewAuthCode($authCode);
340343

src/Server/Grants/PreAuthCodeGrant.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function respondToAccessTokenRequest(
142142
throw OidcServerException::invalidGrant('Invalid pre-authorized code.');
143143
}
144144

145-
if (!$preAuthorizedCode->isPreAuthorized()) {
145+
if (!$preAuthorizedCode->isVciPreAuthorized()) {
146146
$this->loggerService->error(
147147
'Pre-authorized code is not pre-authorized. Value was: ' . $preAuthorizedCodeId,
148148
);

src/Services/DatabaseMigration.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ public function migrate(): void
174174
$this->version20250908163000();
175175
$this->database->write("INSERT INTO $versionsTablename (version) VALUES ('20250908163000')");
176176
}
177+
178+
if (!in_array('20250912163000', $versions, true)) {
179+
$this->version20250912163000();
180+
$this->database->write("INSERT INTO $versionsTablename (version) VALUES ('20250912163000')");
181+
}
177182
}
178183

179184
private function versionsTableName(): string
@@ -571,6 +576,21 @@ private function version20250908163000(): void
571576
,);
572577
}
573578

579+
private function version20250912163000(): void
580+
{
581+
$authCodeTableName = $this->database->applyPrefix(AuthCodeRepository::TABLE_NAME);
582+
$this->database->write(<<< EOT
583+
ALTER TABLE {$authCodeTableName}
584+
DROP COLUMN is_pre_authorized;
585+
EOT
586+
,);
587+
$this->database->write(<<< EOT
588+
ALTER TABLE {$authCodeTableName}
589+
ADD flow_type CHAR(64) NULL;
590+
EOT
591+
,);
592+
}
593+
574594
/**
575595
* @param string[] $columnNames
576596
*/

tests/unit/src/Entities/AuthCodeEntityTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public function testCanGetState(): void
9898
'is_revoked' => false,
9999
'redirect_uri' => 'https://localhost/redirect',
100100
'nonce' => 'nonce',
101-
'is_pre_authorized' => false,
101+
'flow_type' => null,
102102
'tx_code' => null,
103103
],
104104
);

0 commit comments

Comments
 (0)