Skip to content

Commit e960b60

Browse files
committed
Add types to request rules
1 parent bdf24d9 commit e960b60

50 files changed

Lines changed: 232 additions & 224 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Controllers/PushedAuthorizationController.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,7 @@ protected function resolveParametersToPersist(
171171
if ($requestObjectResult !== null) {
172172
// Request Object (JAR) was used. Per RFC 9126, all authorization request parameters must appear
173173
// as claims of the Request Object, so only use its (validated) payload.
174-
/** @psalm-suppress MixedAssignment */
175174
$parameters = $resultBag->getOrFail(RequestObjectRule::class)->getValue();
176-
$parameters = is_array($parameters) ? $parameters : [];
177175

178176
/** @psalm-suppress MixedAssignment */
179177
$clientIdClaim = $parameters[ParamsEnum::ClientId->value] ?? null;

src/Server/AuthorizationServer.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,8 @@ public function validateAuthorizationRequest(ServerRequestInterface $request): O
115115
);
116116

117117
// state and redirectUri is used here, so we can return HTTP redirect error in case of invalid response_type.
118-
/** @var ?string $state */
119118
$state = $resultBag->getOrFail(StateRule::class)->getValue();
120-
/** @var string $redirectUri */
121119
$redirectUri = $resultBag->getOrFail(ClientRedirectUriRule::class)->getValue();
122-
/** @var \SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface $responseMode */
123120
$responseMode = $resultBag->getOrFail(ResponseModeRule::class)->getValue();
124121

125122
foreach ($this->enabledGrantTypes as $grantType) {
@@ -192,11 +189,8 @@ public function validateLogoutRequest(ServerRequestInterface $request): LogoutRe
192189
throw new BadRequest($reason);
193190
}
194191

195-
/** @var \SimpleSAML\OpenID\Core\IdToken|null $idTokenHint */
196192
$idTokenHint = $resultBag->getOrFail(IdTokenHintRule::class)->getValue();
197-
/** @var string|null $postLogoutRedirectUri */
198193
$postLogoutRedirectUri = $resultBag->getOrFail(PostLogoutRedirectUriRule::class)->getValue();
199-
/** @var string|null $state */
200194
$state = $resultBag->getOrFail(StateRule::class)->getValue();
201195
/** @var string|null $uiLocales */
202196
$uiLocales = $resultBag->getOrFail(UiLocalesRule::class)->getValue();

src/Server/Grants/AuthCodeGrant.php

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -525,12 +525,10 @@ public function respondToAccessTokenRequest(
525525
// it is predefined as the ClientRule result and authenticated against by ClientAuthenticationRule above.
526526
$client = $authorizationClientEntity;
527527

528-
/** @var ?ResolvedClientAuthenticationMethod $resolvedClientAuthenticationMethod */
529528
$resolvedClientAuthenticationMethod = $authorizationClientEntity->isGeneric() ?
530529
null :
531530
$resultBag->getOrFail(ClientAuthenticationRule::class)->getValue();
532531

533-
/** @var ?string $codeVerifier */
534532
$codeVerifier = $resultBag->getOrFail(CodeVerifierRule::class)->getValue();
535533

536534
$utilizedClientAuthenticationParams = [];
@@ -777,13 +775,9 @@ public function validateAuthorizationRequestWithRequestRules(
777775
// Since we have already validated redirect_uri, and we have state, make it available for other checkers.
778776
$this->requestRulesManager->predefineResultBag($resultBag);
779777

780-
/** @var string $redirectUri */
781778
$redirectUri = $resultBag->getOrFail(ClientRedirectUriRule::class)->getValue();
782-
/** @var string|null $state */
783779
$state = $resultBag->getOrFail(StateRule::class)->getValue();
784-
/** @var \SimpleSAML\Module\oidc\Entities\Interfaces\ClientEntityInterface $client */
785780
$client = $resultBag->getOrFail(ClientRule::class)->getValue();
786-
/** @var \SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface $responseMode */
787781
$responseMode = $resultBag->getOrFail(ResponseModeRule::class)->getValue();
788782

789783
$this->loggerService->debug('AuthCodeGrant: Resolved data:', [
@@ -805,7 +799,6 @@ public function validateAuthorizationRequestWithRequestRules(
805799

806800
$this->loggerService->debug('AuthCodeGrant: executed rules.', ['rulesToExecute' => $rulesToExecute]);
807801

808-
/** @var \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes */
809802
$scopes = $resultBag->getOrFail(ScopeRule::class)->getValue();
810803

811804
$this->loggerService->debug('AuthCodeGrant: Resolved scopes: ', ['scopes' => $scopes]);
@@ -821,13 +814,11 @@ public function validateAuthorizationRequestWithRequestRules(
821814
$oAuth2AuthorizationRequest->setState($state);
822815
}
823816

824-
/** @var ?string $codeChallenge */
825817
$codeChallenge = $resultBag->getOrFail(CodeChallengeRule::class)->getValue();
826818
if ($codeChallenge) {
827819
$this->loggerService->debug('AuthCodeGrant: Code challenge: ', [
828820
'codeChallenge' => $codeChallenge,
829821
]);
830-
/** @var string $codeChallengeMethod */
831822
$codeChallengeMethod = $resultBag->getOrFail(CodeChallengeMethodRule::class)->getValue();
832823

833824
$oAuth2AuthorizationRequest->setCodeChallenge($codeChallenge);
@@ -879,7 +870,7 @@ public function validateAuthorizationRequestWithRequestRules(
879870
$maxAge = $resultBag->get(MaxAgeRule::class);
880871
$this->loggerService->debug('AuthCodeGrant: MaxAge: ', ['maxAge' => $maxAge]);
881872
if (null !== $maxAge) {
882-
$authorizationRequest->setAuthTime((int) $maxAge->getValue());
873+
$authorizationRequest->setAuthTime($maxAge->getValue());
883874
}
884875

885876
$requestClaims = $resultBag->get(RequestedClaimsRule::class);
@@ -892,7 +883,6 @@ public function validateAuthorizationRequestWithRequestRules(
892883
}
893884
}
894885

895-
/** @var array|null $acrValues */
896886
$acrValues = $resultBag->getOrFail(AcrValuesRule::class)->getValue();
897887
$this->loggerService->debug('AuthCodeGrant: ACR values: ', ['acrValues' => $acrValues]);
898888
$authorizationRequest->setRequestedAcrValues($acrValues);
@@ -904,20 +894,17 @@ public function validateAuthorizationRequestWithRequestRules(
904894
$this->loggerService->debug('AuthCodeGrant: FlowType: ', ['flowType' => $flowType]);
905895
$authorizationRequest->setFlowType($flowType);
906896

907-
/** @var ?string $issuerState */
908897
$issuerState = $resultBag->get(IssuerStateRule::class)?->getValue();
909898
$this->loggerService->debug('AuthCodeGrant: Issuer state: ', ['issuerState' => $issuerState]);
910899
$authorizationRequest->setIssuerState($issuerState);
911900

912-
/** @var ?array $authorizationDetails */
913901
$authorizationDetails = $resultBag->get(AuthorizationDetailsRule::class)?->getValue();
914902
$this->loggerService->debug(
915903
'AuthCodeGrant: Authorization details: ',
916904
['authorizationDetails' => $authorizationDetails],
917905
);
918906
$authorizationRequest->setAuthorizationDetails($authorizationDetails);
919907

920-
/** @var \SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface $responseMode */
921908
$responseMode = $resultBag->getOrFail(ResponseModeRule::class)->getValue();
922909
$this->loggerService->debug(
923910
'AuthCodeGrant: Response mode: ',
@@ -955,7 +942,6 @@ public function validateAuthorizationRequestWithRequestRules(
955942
['genericClientId' => $client->getIdentifier()],
956943
);
957944
// The generic client was used. Make sure to store actually used client_id and redirect_uri params.
958-
/** @var string $clientIdParam */
959945
$clientIdParam = $resultBag->getOrFail(ClientIdRule::class)->getValue();
960946
$this->loggerService->debug(
961947
'AuthCodeGrant: Binding client_id param to request: ',

src/Server/Grants/ImplicitGrant.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,9 @@ public function validateAuthorizationRequestWithRequestRules(
137137

138138
$this->requestRulesManager->predefineResultBag($resultBag);
139139

140-
/** @var string $redirectUri */
141140
$redirectUri = $resultBag->getOrFail(ClientRedirectUriRule::class)->getValue();
142-
/** @var string|null $state */
143141
$state = $resultBag->getOrFail(StateRule::class)->getValue();
144-
/** @var \SimpleSAML\Module\oidc\Entities\Interfaces\ClientEntityInterface $client */
145142
$client = $resultBag->getOrFail(ClientRule::class)->getValue();
146-
/** @var \SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface $responseMode */
147143
$responseMode = $resultBag->getOrFail(ResponseModeRule::class)->getValue();
148144

149145
// Some rules need certain things available in order to work properly...
@@ -157,7 +153,6 @@ public function validateAuthorizationRequestWithRequestRules(
157153
$this->allowedAuthorizationHttpMethods,
158154
);
159155

160-
/** @var \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes */
161156
$scopes = $resultBag->getOrFail(ScopeRule::class)->getValue();
162157

163158
$authorizationRequest = new AuthorizationRequest();
@@ -170,11 +165,11 @@ public function validateAuthorizationRequestWithRequestRules(
170165
}
171166

172167
// nonce existence is validated using a rule, so we can get it from there.
173-
$authorizationRequest->setNonce((string)$resultBag->getOrFail(RequiredNonceRule::class)->getValue());
168+
$authorizationRequest->setNonce($resultBag->getOrFail(RequiredNonceRule::class)->getValue());
174169

175170
$maxAge = $resultBag->get(MaxAgeRule::class);
176171
if (null !== $maxAge) {
177-
$authorizationRequest->setAuthTime((int) $maxAge->getValue());
172+
$authorizationRequest->setAuthTime($maxAge->getValue());
178173
}
179174

180175
$requestClaims = $resultBag->get(RequestedClaimsRule::class);
@@ -185,19 +180,15 @@ public function validateAuthorizationRequestWithRequestRules(
185180
$authorizationRequest->setClaims($requestClaimValues);
186181
}
187182
}
188-
/** @var bool $addClaimsToIdToken */
189183
$addClaimsToIdToken = ($resultBag->getOrFail(AddClaimsToIdTokenRule::class))->getValue();
190184
$authorizationRequest->setAddClaimsToIdToken($addClaimsToIdToken);
191185

192-
/** @var string $responseType */
193186
$responseType = ($resultBag->getOrFail(ResponseTypeRule::class))->getValue();
194187
$authorizationRequest->setResponseType($responseType);
195188

196-
/** @var array|null $acrValues */
197189
$acrValues = $resultBag->getOrFail(AcrValuesRule::class)->getValue();
198190
$authorizationRequest->setRequestedAcrValues($acrValues);
199191

200-
/** @var \SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface $responseMode */
201192
$responseMode = $resultBag->getOrFail(ResponseModeRule::class)->getValue();
202193
$authorizationRequest->setResponseMode($responseMode);
203194

src/Server/Grants/PreAuthCodeGrant.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ public function respondToAccessTokenRequest(
187187
$this->allowedTokenHttpMethods,
188188
);
189189

190-
/** @var ?array $authorizationDetails */
191190
$authorizationDetails = $resultBag->get(AuthorizationDetailsRule::class)?->getValue();
192191

193192
// Issue and persist new access token

src/Server/RequestRules/Interfaces/RequestRuleInterface.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@
55
namespace SimpleSAML\Module\oidc\Server\RequestRules\Interfaces;
66

77
use Psr\Http\Message\ServerRequestInterface;
8+
use SimpleSAML\Module\oidc\Server\RequestRules\Result;
89
use SimpleSAML\Module\oidc\Server\ResponseModes\QueryResponseMode;
910
use SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface;
1011
use SimpleSAML\Module\oidc\Services\LoggerService;
1112
use SimpleSAML\OpenID\Codebooks\HttpMethodsEnum;
1213

14+
/**
15+
* The generic parameter T describes the type of value the rule yields into the result bag. It is
16+
* bound by each concrete rule (via `@extends AbstractRule<...>`) and consumed by the ResultBag,
17+
* which uses it to infer the value type when a result is fetched by its rule class-string.
18+
*
19+
* @template-covariant T
20+
*/
1321
interface RequestRuleInterface
1422
{
1523
/**
@@ -27,7 +35,8 @@ public function getKey(): string;
2735
* @param ResponseModeInterface $responseMode Response mode to use for error responses
2836
* @param HttpMethodsEnum[] $allowedServerRequestMethods Indicate allowed HTTP methods used for request
2937
*
30-
* @return \SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultInterface|null Result of the specific check
38+
* @return \SimpleSAML\Module\oidc\Server\RequestRules\Result<mixed>|null Result of the specific check
39+
* (the concrete value type T is bound per rule and surfaced via the ResultBag accessors)
3140
*
3241
* @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException If check fails
3342
*/
@@ -38,5 +47,5 @@ public function checkRule(
3847
array $data = [],
3948
ResponseModeInterface $responseMode = new QueryResponseMode(),
4049
array $allowedServerRequestMethods = [HttpMethodsEnum::GET],
41-
): ?ResultInterface;
50+
): ?Result;
4251
}

src/Server/RequestRules/Interfaces/ResultBagInterface.php

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,56 @@
44

55
namespace SimpleSAML\Module\oidc\Server\RequestRules\Interfaces;
66

7+
use SimpleSAML\Module\oidc\Server\RequestRules\Result;
8+
79
interface ResultBagInterface
810
{
911
/**
1012
* Add result to the result bag.
13+
*
14+
* @param \SimpleSAML\Module\oidc\Server\RequestRules\Result<mixed> $result
1115
*/
12-
public function add(ResultInterface $result): void;
16+
public function add(Result $result): void;
1317

1418
/**
1519
* Get specific result or null if it doesn't exist.
20+
*
21+
* The value type is inferred from the rule class-string passed as the key.
22+
*
23+
* @template T
24+
* @param class-string<RequestRuleInterface<T>> $key
25+
* @return \SimpleSAML\Module\oidc\Server\RequestRules\Result<T>|null
26+
*/
27+
public function get(string $key): ?Result;
28+
29+
/**
30+
* Get specific result or fail if it doesn't exist.
31+
*
32+
* The value type is inferred from the rule class-string passed as the key.
33+
*
34+
* @template T
35+
* @param class-string<RequestRuleInterface<T>> $key
36+
* @return \SimpleSAML\Module\oidc\Server\RequestRules\Result<T>
37+
* @throws \Throwable If result with specific key is not present.
1638
*/
17-
public function get(string $key): ?ResultInterface;
39+
public function getOrFail(string $key): Result;
1840

1941
/**
20-
* Get specific result or fail if it doesn't exits.
42+
* Get the value of a specific result or fail if the result doesn't exist.
43+
*
44+
* Convenience accessor that skips the intermediate Result object. The value type is inferred
45+
* from the rule class-string passed as the key.
46+
*
47+
* @template T
48+
* @param class-string<RequestRuleInterface<T>> $key
49+
* @return T
2150
* @throws \Throwable If result with specific key is not present.
2251
*/
23-
public function getOrFail(string $key): ResultInterface;
52+
public function getValueOrFail(string $key): mixed;
2453

2554
/**
2655
* Get all results.
27-
* @return \SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultInterface[]
56+
* @return array<string, \SimpleSAML\Module\oidc\Server\RequestRules\Result<mixed>>
2857
*/
2958
public function getAll(): array;
3059

src/Server/RequestRules/Interfaces/ResultInterface.php

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Server/RequestRules/RequestRulesManager.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Psr\Http\Message\ServerRequestInterface;
99
use SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\RequestRuleInterface;
1010
use SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultBagInterface;
11-
use SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultInterface;
1211
use SimpleSAML\Module\oidc\Server\ResponseModes\QueryResponseMode;
1312
use SimpleSAML\Module\oidc\Server\ResponseModes\ResponseModeInterface;
1413
use SimpleSAML\Module\oidc\Services\LoggerService;
@@ -84,7 +83,7 @@ public function check(
8483
/**
8584
* Predefine (add) the existing result, so it can be used by other checkers during check.
8685
*/
87-
public function predefineResult(ResultInterface $result): void
86+
public function predefineResult(Result $result): void
8887
{
8988
$this->resultBag->add($result);
9089
}

src/Server/RequestRules/Result.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44

55
namespace SimpleSAML\Module\oidc\Server\RequestRules;
66

7-
use SimpleSAML\Module\oidc\Server\RequestRules\Interfaces\ResultInterface;
8-
9-
class Result implements ResultInterface
7+
/**
8+
* Result of a single request rule check.
9+
*
10+
* The generic parameter T describes the type of the contained value. Each rule binds it via
11+
* its `@extends AbstractRule<...>` annotation, which in turn lets the ResultBag infer the value
12+
* type when a result is fetched by its rule class-string.
13+
*
14+
* @template-covariant T
15+
*/
16+
class Result
1017
{
1118
/**
12-
* Result constructor.
13-
* @param mixed|null $value
19+
* @param T $value
1420
*/
1521
public function __construct(protected string $key, protected mixed $value = null)
1622
{
@@ -21,13 +27,11 @@ public function getKey(): string
2127
return $this->key;
2228
}
2329

30+
/**
31+
* @return T
32+
*/
2433
public function getValue(): mixed
2534
{
2635
return $this->value;
2736
}
28-
29-
public function setValue(mixed $value): void
30-
{
31-
$this->value = $value;
32-
}
3337
}

0 commit comments

Comments
 (0)