Skip to content

Commit cc1256d

Browse files
committed
WIP Authorization Details in AuthCode
1 parent 2fc22b0 commit cc1256d

File tree

12 files changed

+257
-24
lines changed

12 files changed

+257
-24
lines changed

docker/conformance.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ CREATE TABLE oidc_auth_code (
8484
redirect_uri TEXT NOT NULL, nonce TEXT NULL,
8585
flow_type CHAR(64) DEFAULT NULL,
8686
tx_code varchar(191) DEFAULT NULL,
87+
authorization_details TEXT NULL,
8788
CONSTRAINT FK_97D32CA7A76ED395 FOREIGN KEY (user_id)
8889
REFERENCES oidc_user (id) ON DELETE CASCADE,
8990
CONSTRAINT FK_97D32CA719EB6921 FOREIGN KEY (client_id)

src/Entities/AuthCodeEntity.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public function __construct(
4646
bool $isRevoked = false,
4747
protected readonly ?FlowTypeEnum $flowTypeEnum = null,
4848
protected readonly ?string $txCode = null,
49+
protected readonly ?array $authorizationDetails = null,
4950
) {
5051
$this->identifier = $id;
5152
$this->client = $client;
@@ -73,6 +74,7 @@ public function getState(): array
7374
'nonce' => $this->getNonce(),
7475
'flow_type' => $this->flowTypeEnum?->value,
7576
'tx_code' => $this->txCode,
77+
'authorization_details' => json_encode($this->authorizationDetails, JSON_THROW_ON_ERROR),
7678
];
7779
}
7880

@@ -90,4 +92,9 @@ public function getFlowTypeEnum(): ?FlowTypeEnum
9092
{
9193
return $this->flowTypeEnum;
9294
}
95+
96+
public function getAuthorizationDetails(): ?array
97+
{
98+
return $this->authorizationDetails;
99+
}
93100
}

src/Entities/Interfaces/AuthCodeEntityInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use League\OAuth2\Server\Entities\AuthCodeEntityInterface as OAuth2AuthCodeEntityInterface;
88

9-
interface AuthCodeEntityInterface extends OAuth2AuthCodeEntityInterface
9+
interface AuthCodeEntityInterface extends OAuth2AuthCodeEntityInterface, TokenRevokableInterface
1010
{
1111
/**
1212
* @return string|null

src/Factories/Entities/AuthCodeEntityFactory.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function fromData(
3434
bool $isRevoked = false,
3535
?FlowTypeEnum $flowTypeEnum = null,
3636
?string $txCode = null,
37+
?array $authorizationDetails = null,
3738
): AuthCodeEntity {
3839
return new AuthCodeEntity(
3940
$id,
@@ -46,6 +47,7 @@ public function fromData(
4647
$isRevoked,
4748
$flowTypeEnum,
4849
$txCode,
50+
$authorizationDetails,
4951
);
5052
}
5153

@@ -89,6 +91,12 @@ public function fromState(array $state): AuthCodeEntity
8991
$flowType = empty($state['flow_type']) ? null : FlowTypeEnum::tryFrom((string)$state['flow_type']);
9092
$txCode = empty($state['tx_code']) ? null : (string)$state['tx_code'];
9193

94+
/** @psalm-suppress MixedAssignment */
95+
$authorizationDetails = isset($state['authorization_details']) && is_string($state['authorization_details']) ?
96+
json_decode($state['authorization_details'], true, 512, JSON_THROW_ON_ERROR) :
97+
null;
98+
$authorizationDetails = is_array($authorizationDetails) ? $authorizationDetails : null;
99+
92100
return $this->fromData(
93101
$id,
94102
$client,
@@ -100,6 +108,7 @@ public function fromState(array $state): AuthCodeEntity
100108
$isRevoked,
101109
$flowType,
102110
$txCode,
111+
$authorizationDetails,
103112
);
104113
}
105114
}

src/Factories/RequestRulesManagerFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
1616
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AcrValuesRule;
1717
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AddClaimsToIdTokenRule;
18+
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AuthorizationDetailsRule;
1819
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\ClientAuthenticationRule;
1920
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\ClientRule;
2021
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeChallengeMethodRule;
@@ -146,6 +147,7 @@ private function getDefaultRules(): array
146147
),
147148
new CodeVerifierRule($this->requestParamsResolver, $this->helpers),
148149
new IssuerStateRule($this->requestParamsResolver, $this->helpers, $this->issuerStateRepository),
150+
new AuthorizationDetailsRule($this->requestParamsResolver, $this->helpers, $this->moduleConfig),
149151
];
150152
}
151153
}

src/Repositories/AuthCodeRepository.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ public function persistNewAuthCode(OAuth2AuthCodeEntityInterface $authCodeEntity
8181
redirect_uri,
8282
nonce,
8383
flow_type,
84-
tx_code
84+
tx_code,
85+
authorization_details
8586
) VALUES (
8687
:id,
8788
:scopes,
@@ -92,7 +93,8 @@ public function persistNewAuthCode(OAuth2AuthCodeEntityInterface $authCodeEntity
9293
:redirect_uri,
9394
:nonce,
9495
:flow_type,
95-
:tx_code
96+
:tx_code,
97+
:authorization_details
9698
)
9799
EOS,
98100
$this->getTableName(),
@@ -116,7 +118,7 @@ public function persistNewAuthCode(OAuth2AuthCodeEntityInterface $authCodeEntity
116118
* Find Auth Code by id.
117119
* @throws \Exception
118120
*/
119-
public function findById(string $codeId): ?AuthCodeEntityInterface
121+
public function findById(string $codeId): ?AuthCodeEntity
120122
{
121123
/** @var ?array $data */
122124
$data = $this->protocolCache?->get(null, $this->getCacheKey($codeId));
@@ -215,7 +217,8 @@ private function update(AuthCodeEntity $authCodeEntity): void
215217
redirect_uri = :redirect_uri,
216218
nonce = :nonce,
217219
flow_type = :flow_type,
218-
tx_code = :tx_code
220+
tx_code = :tx_code,
221+
authorization_details = :authorization_details
219222
WHERE id = :id
220223
EOS
221224
,

src/Server/Grants/AuthCodeGrant.php

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@
2222
use LogicException;
2323
use Psr\Http\Message\ServerRequestInterface;
2424
use SimpleSAML\Module\oidc\Codebooks\FlowTypeEnum;
25+
use SimpleSAML\Module\oidc\Entities\AuthCodeEntity;
2526
use SimpleSAML\Module\oidc\Entities\Interfaces\AccessTokenEntityInterface;
2627
use SimpleSAML\Module\oidc\Entities\Interfaces\AuthCodeEntityInterface;
2728
use SimpleSAML\Module\oidc\Entities\Interfaces\RefreshTokenEntityInterface;
2829
use SimpleSAML\Module\oidc\Entities\UserEntity;
2930
use SimpleSAML\Module\oidc\Factories\Entities\AccessTokenEntityFactory;
3031
use SimpleSAML\Module\oidc\Factories\Entities\AuthCodeEntityFactory;
3132
use SimpleSAML\Module\oidc\Helpers;
33+
use SimpleSAML\Module\oidc\Repositories\AuthCodeRepository;
3234
use SimpleSAML\Module\oidc\Repositories\Interfaces\AccessTokenRepositoryInterface;
3335
use SimpleSAML\Module\oidc\Repositories\Interfaces\AuthCodeRepositoryInterface;
3436
use SimpleSAML\Module\oidc\Repositories\Interfaces\RefreshTokenRepositoryInterface;
@@ -40,6 +42,7 @@
4042
use SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultBagInterface;
4143
use SimpleSAML\Module\oidc\Server\RequestRules\RequestRulesManager;
4244
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AcrValuesRule;
45+
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\AuthorizationDetailsRule;
4346
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\ClientAuthenticationRule;
4447
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\ClientRule;
4548
use SimpleSAML\Module\oidc\Server\RequestRules\Rules\CodeChallengeMethodRule;
@@ -288,6 +291,8 @@ public function completeOidcAuthorizationRequest(
288291
'claims' => $authorizationRequest->getClaims(),
289292
'acr' => $authorizationRequest->getAcr(),
290293
'session_id' => $authorizationRequest->getSessionId(),
294+
// Do not add anything else to the payload, as it will make it dangerously long to send it as a query
295+
// parameter. Use storage instead.
291296
];
292297

293298
$jsonPayload = json_encode($payload, JSON_THROW_ON_ERROR);
@@ -338,6 +343,7 @@ protected function issueOidcAuthCode(
338343
$redirectUri,
339344
$authorizationRequest->getNonce(),
340345
flowTypeEnum: $flowType,
346+
authorizationDetails: $authorizationRequest->getAuthorizationDetails(),
341347
);
342348
$this->authCodeRepository->persistNewAuthCode($authCode);
343349

@@ -448,7 +454,21 @@ public function respondToAccessTokenRequest(
448454
*/
449455
$authCodePayload = json_decode($this->decrypt($encryptedAuthCode), null, 512, JSON_THROW_ON_ERROR);
450456

451-
$this->validateAuthorizationCode($authCodePayload, $client, $request);
457+
if (!property_exists($authCodePayload, 'auth_code_id')) {
458+
throw OAuthServerException::invalidRequest('code', 'Authorization code malformed');
459+
}
460+
461+
if (! is_a($this->authCodeRepository, AuthCodeRepository::class)) {
462+
throw OidcServerException::serverError('Unexpected auth code repository entity type.');
463+
}
464+
465+
$storedAuthCodeEntity = $this->authCodeRepository->findById($authCodePayload->auth_code_id);
466+
467+
if ($storedAuthCodeEntity === null) {
468+
throw OAuthServerException::invalidGrant('Authorization code not found');
469+
}
470+
471+
$this->validateAuthorizationCode($authCodePayload, $client, $request, $storedAuthCodeEntity);
452472

453473
$scopes = $this->scopeRepository->finalizeScopes(
454474
$this->validateScopes($authCodePayload->scopes),
@@ -569,9 +589,6 @@ public function respondToAccessTokenRequest(
569589
$responseType->setRefreshToken($refreshToken);
570590
}
571591
}
572-
if (! is_a($this->authCodeRepository, AuthCodeRepositoryInterface::class)) {
573-
throw OidcServerException::serverError('Unexpected auth code repository entity type.');
574-
}
575592

576593
// Revoke used auth code
577594
$this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id);
@@ -592,20 +609,13 @@ protected function validateAuthorizationCode(
592609
object $authCodePayload,
593610
OAuth2ClientEntityInterface $client,
594611
ServerRequestInterface $request,
612+
AuthCodeEntity $storedAuthCodeEntity,
595613
): void {
596614
/**
597615
* @noinspection PhpUndefinedClassInspection
598616
* @psalm-var AuthCodePayloadObject $authCodePayload
599617
*/
600618

601-
if (!property_exists($authCodePayload, 'auth_code_id')) {
602-
throw OAuthServerException::invalidRequest('code', 'Authorization code malformed');
603-
}
604-
605-
if (! is_a($this->authCodeRepository, AuthCodeRepositoryInterface::class)) {
606-
throw OidcServerException::serverError('Unexpected auth code repository entity type.');
607-
}
608-
609619
if (! is_a($this->accessTokenRepository, AccessTokenRepositoryInterface::class)) {
610620
throw OidcServerException::serverError('Unexpected access token repository entity type.');
611621
}
@@ -618,7 +628,7 @@ protected function validateAuthorizationCode(
618628
throw OAuthServerException::invalidGrant('Authorization code has expired');
619629
}
620630

621-
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
631+
if ($storedAuthCodeEntity->isRevoked()) {
622632
// Code is reused, all related tokens must be revoked, per https://tools.ietf.org/html/rfc6749#section-4.1.2
623633
$this->accessTokenRepository->revokeByAuthCodeId($authCodePayload->auth_code_id);
624634
$this->refreshTokenRepository->revokeByAuthCodeId($authCodePayload->auth_code_id);
@@ -663,6 +673,7 @@ public function validateAuthorizationRequestWithRequestRules(
663673
CodeChallengeRule::class,
664674
CodeChallengeMethodRule::class,
665675
IssuerStateRule::class,
676+
AuthorizationDetailsRule::class,
666677
];
667678

668679
// Since we have already validated redirect_uri, and we have state, make it available for other checkers.
@@ -710,7 +721,15 @@ public function validateAuthorizationRequestWithRequestRules(
710721
$oAuth2AuthorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
711722
}
712723

713-
if (! $this->isOidcCandidate($oAuth2AuthorizationRequest)) {
724+
$isVciAuthorizationCodeRequest = $this->requestParamsResolver->isVciAuthorizationCodeRequest(
725+
$request,
726+
$this->allowedAuthorizationHttpMethods,
727+
);
728+
729+
if (
730+
(! $this->isOidcCandidate($oAuth2AuthorizationRequest)) &&
731+
(! $isVciAuthorizationCodeRequest)
732+
) {
714733
return $oAuth2AuthorizationRequest;
715734
}
716735

@@ -743,17 +762,22 @@ public function validateAuthorizationRequestWithRequestRules(
743762
$acrValues = $resultBag->getOrFail(AcrValuesRule::class)->getValue();
744763
$authorizationRequest->setRequestedAcrValues($acrValues);
745764

746-
$authorizationRequest->setIsVciRequest(
747-
$this->requestParamsResolver->isVciAuthorizationCodeRequest(
748-
$request,
749-
$this->allowedAuthorizationHttpMethods,
750-
),
765+
766+
$authorizationRequest->setIsVciRequest($isVciAuthorizationCodeRequest);
767+
$authorizationRequest->setFlowType(
768+
$isVciAuthorizationCodeRequest ?
769+
FlowTypeEnum::VciAuthorizationCode :
770+
FlowTypeEnum::OidcAuthorizationCode,
751771
);
752772

753773
/** @var ?string $issuerState */
754774
$issuerState = $resultBag->get(IssuerStateRule::class)?->getValue();
755775
$authorizationRequest->setIssuerState($issuerState);
756776

777+
/** @var ?array $authorizationDetails */
778+
$authorizationDetails = $resultBag->get(AuthorizationDetailsRule::class)?->getValue();
779+
$authorizationRequest->setAuthorizationDetails($authorizationDetails);
780+
757781
return $authorizationRequest;
758782
}
759783

src/Server/Grants/PreAuthCodeGrant.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ protected function validateAuthorizationCode(
236236
object $authCodePayload,
237237
OAuth2ClientEntityInterface $client,
238238
ServerRequestInterface $request,
239+
AuthCodeEntity $storedAuthCodeEntity,
239240
): void {
240241
}
241242

0 commit comments

Comments
 (0)