1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Facile\OpenIDClient\Issuer\Metadata; |
||
6 | |||
7 | use function array_diff; |
||
8 | use function array_filter; |
||
9 | use const ARRAY_FILTER_USE_BOTH; |
||
10 | use function array_key_exists; |
||
11 | use function array_keys; |
||
12 | use function array_merge; |
||
13 | use function count; |
||
14 | use Facile\OpenIDClient\Exception\InvalidArgumentException; |
||
15 | use function implode; |
||
16 | |||
17 | /** |
||
18 | * @psalm-import-type IssuerMetadataObject from \Facile\JoseVerifier\Psalm\PsalmTypes |
||
19 | */ |
||
20 | final class IssuerMetadata implements IssuerMetadataInterface |
||
21 | { |
||
22 | /** |
||
23 | * @var array<string, mixed> |
||
24 | * @psalm-var IssuerMetadataObject |
||
25 | */ |
||
26 | private $metadata; |
||
27 | |||
28 | /** @var string[] */ |
||
29 | private static $requiredKeys = [ |
||
30 | 'issuer', |
||
31 | 'authorization_endpoint', |
||
32 | 'jwks_uri', |
||
33 | ]; |
||
34 | |||
35 | /** |
||
36 | * IssuerMetadata constructor. |
||
37 | * |
||
38 | * @param string $issuer |
||
39 | * @param string $authorizationEndpoint |
||
40 | * @param string $jwksUri |
||
41 | * @param array<string, mixed> $claims |
||
42 | */ |
||
43 | 69 | public function __construct( |
|
44 | string $issuer, |
||
45 | string $authorizationEndpoint, |
||
46 | string $jwksUri, |
||
47 | array $claims = [] |
||
48 | ) { |
||
49 | $requiredClaims = [ |
||
50 | 69 | 'issuer' => $issuer, |
|
51 | 69 | 'authorization_endpoint' => $authorizationEndpoint, |
|
52 | 69 | 'jwks_uri' => $jwksUri, |
|
53 | ]; |
||
54 | |||
55 | /** @var IssuerMetadataObject $merged */ |
||
56 | 69 | $merged = array_merge($claims, $requiredClaims); |
|
57 | 69 | $this->metadata = $merged; |
|
0 ignored issues
–
show
|
|||
58 | 69 | } |
|
59 | |||
60 | /** |
||
61 | * @param array<string, mixed> $claims |
||
62 | * |
||
63 | * @return static |
||
64 | * |
||
65 | * @psalm-param IssuerMetadataObject $claims |
||
66 | */ |
||
67 | 1 | public static function fromArray(array $claims): self |
|
68 | { |
||
69 | 1 | $missingKeys = array_diff(self::$requiredKeys, array_keys($claims)); |
|
70 | 1 | if (0 !== count($missingKeys)) { |
|
71 | throw new InvalidArgumentException('Invalid issuer metadata. Missing keys: ' . implode(', ', $missingKeys)); |
||
72 | } |
||
73 | |||
74 | 1 | return new static( |
|
75 | 1 | $claims['issuer'], |
|
76 | 1 | $claims['authorization_endpoint'], |
|
77 | 1 | $claims['jwks_uri'], |
|
78 | $claims |
||
79 | ); |
||
80 | } |
||
81 | |||
82 | 2 | public function getIssuer(): string |
|
83 | { |
||
84 | 2 | return $this->metadata['issuer']; |
|
85 | } |
||
86 | |||
87 | 2 | public function getAuthorizationEndpoint(): string |
|
88 | { |
||
89 | 2 | return $this->metadata['authorization_endpoint']; |
|
90 | } |
||
91 | |||
92 | 1 | public function getTokenEndpoint(): ?string |
|
93 | { |
||
94 | 1 | return $this->metadata['token_endpoint'] ?? null; |
|
95 | } |
||
96 | |||
97 | 1 | public function getUserinfoEndpoint(): ?string |
|
98 | { |
||
99 | 1 | return $this->metadata['userinfo_endpoint'] ?? null; |
|
100 | } |
||
101 | |||
102 | 1 | public function getRegistrationEndpoint(): ?string |
|
103 | { |
||
104 | 1 | return $this->metadata['registration_endpoint'] ?? null; |
|
105 | } |
||
106 | |||
107 | 2 | public function getJwksUri(): string |
|
108 | { |
||
109 | 2 | return $this->metadata['jwks_uri']; |
|
110 | } |
||
111 | |||
112 | 1 | public function getScopesSupported(): ?array |
|
113 | { |
||
114 | 1 | return $this->metadata['scopes_supported'] ?? null; |
|
115 | } |
||
116 | |||
117 | 1 | public function getResponseTypesSupported(): array |
|
118 | { |
||
119 | 1 | return $this->metadata['response_types_supported']; |
|
120 | } |
||
121 | |||
122 | 1 | public function getResponseModesSupported(): array |
|
123 | { |
||
124 | 1 | return $this->metadata['response_modes_supported'] ?? ['query', 'fragment']; |
|
125 | } |
||
126 | |||
127 | 1 | public function getGrantTypesSupported(): array |
|
128 | { |
||
129 | 1 | return $this->metadata['grant_types_supported'] ?? ['authorization_code', 'implicit']; |
|
130 | } |
||
131 | |||
132 | 1 | public function getAcrValuesSupported(): ?array |
|
133 | { |
||
134 | 1 | return $this->metadata['acr_values_supported'] ?? null; |
|
135 | } |
||
136 | |||
137 | 1 | public function getSubjectTypesSupported(): array |
|
138 | { |
||
139 | 1 | return $this->metadata['subject_types_supported'] ?? ['public']; |
|
140 | } |
||
141 | |||
142 | 1 | public function getDisplayValuesSupported(): ?array |
|
143 | { |
||
144 | 1 | return $this->metadata['display_values_supported'] ?? null; |
|
145 | } |
||
146 | |||
147 | 1 | public function getClaimTypesSupported(): array |
|
148 | { |
||
149 | 1 | return $this->metadata['claim_types_supported'] ?? ['normal']; |
|
150 | } |
||
151 | |||
152 | 1 | public function getClaimsSupported(): ?array |
|
153 | { |
||
154 | 1 | return $this->metadata['claims_supported'] ?? null; |
|
155 | } |
||
156 | |||
157 | 1 | public function getServiceDocumentation(): ?string |
|
158 | { |
||
159 | 1 | return $this->metadata['service_documentation'] ?? null; |
|
160 | } |
||
161 | |||
162 | 1 | public function getClaimsLocalesSupported(): ?array |
|
163 | { |
||
164 | 1 | return $this->metadata['claims_locales_supported'] ?? null; |
|
165 | } |
||
166 | |||
167 | 1 | public function getUiLocalesSupported(): ?array |
|
168 | { |
||
169 | 1 | return $this->metadata['ui_locales_supported'] ?? null; |
|
170 | } |
||
171 | |||
172 | 2 | public function isClaimsParameterSupported(): bool |
|
173 | { |
||
174 | 2 | return $this->metadata['claims_parameter_supported'] ?? false; |
|
175 | } |
||
176 | |||
177 | 2 | public function isRequestParameterSupported(): bool |
|
178 | { |
||
179 | 2 | return $this->metadata['request_parameter_supported'] ?? false; |
|
180 | } |
||
181 | |||
182 | 2 | public function isRequestUriParameterSupported(): bool |
|
183 | { |
||
184 | 2 | return $this->metadata['request_uri_parameter_supported'] ?? false; |
|
185 | } |
||
186 | |||
187 | 2 | public function isRequireRequestUriRegistration(): bool |
|
188 | { |
||
189 | 2 | return $this->metadata['require_request_uri_registration'] ?? true; |
|
190 | } |
||
191 | |||
192 | 1 | public function getOpPolicyUri(): ?string |
|
193 | { |
||
194 | 1 | return $this->metadata['op_policy_uri'] ?? null; |
|
195 | } |
||
196 | |||
197 | 1 | public function getOpTosUri(): ?string |
|
198 | { |
||
199 | 1 | return $this->metadata['op_tos_uri'] ?? null; |
|
200 | } |
||
201 | |||
202 | 1 | public function getCodeChallengeMethodsSupported(): ?array |
|
203 | { |
||
204 | 1 | return $this->metadata['code_challenge_methods_supported'] ?? null; |
|
205 | } |
||
206 | |||
207 | 1 | public function getTokenEndpointAuthMethodsSupported(): array |
|
208 | { |
||
209 | 1 | return $this->metadata['token_endpoint_auth_methods_supported'] ?? ['client_secret_basic']; |
|
210 | } |
||
211 | |||
212 | 1 | public function getTokenEndpointAuthSigningAlgValuesSupported(): array |
|
213 | { |
||
214 | /** @var list<non-empty-string> $default */ |
||
215 | 1 | $default = ['RS256']; |
|
216 | |||
217 | 1 | return $this->metadata['token_endpoint_auth_signing_alg_values_supported'] ?? $default; |
|
0 ignored issues
–
show
|
|||
218 | } |
||
219 | |||
220 | 1 | public function getIdTokenSigningAlgValuesSupported(): array |
|
221 | { |
||
222 | /** @var list<non-empty-string> $default */ |
||
223 | 1 | $default = ['RS256']; |
|
224 | |||
225 | 1 | return $this->metadata['id_token_signing_alg_values_supported'] ?? $default; |
|
0 ignored issues
–
show
|
|||
226 | } |
||
227 | |||
228 | 1 | public function getIdTokenEncryptionAlgValuesSupported(): array |
|
229 | { |
||
230 | 1 | return $this->metadata['id_token_encryption_alg_values_supported'] ?? []; |
|
231 | } |
||
232 | |||
233 | 1 | public function getIdTokenEncryptionEncValuesSupported(): array |
|
234 | { |
||
235 | 1 | return $this->metadata['id_token_encryption_enc_values_supported'] ?? []; |
|
236 | } |
||
237 | |||
238 | 1 | public function getUserinfoSigningAlgValuesSupported(): array |
|
239 | { |
||
240 | 1 | return $this->metadata['userinfo_signing_alg_values_supported'] ?? []; |
|
241 | } |
||
242 | |||
243 | 1 | public function getUserinfoEncryptionAlgValuesSupported(): array |
|
244 | { |
||
245 | 1 | return $this->metadata['userinfo_encryption_alg_values_supported'] ?? []; |
|
246 | } |
||
247 | |||
248 | 1 | public function getUserinfoEncryptionEncValuesSupported(): array |
|
249 | { |
||
250 | 1 | return $this->metadata['userinfo_encryption_enc_values_supported'] ?? []; |
|
251 | } |
||
252 | |||
253 | 1 | public function getAuthorizationSigningAlgValuesSupported(): array |
|
254 | { |
||
255 | 1 | return $this->metadata['authorization_signing_alg_values_supported'] ?? []; |
|
256 | } |
||
257 | |||
258 | 1 | public function getAuthorizationEncryptionAlgValuesSupported(): array |
|
259 | { |
||
260 | 1 | return $this->metadata['authorization_encryption_alg_values_supported'] ?? []; |
|
261 | } |
||
262 | |||
263 | 1 | public function getAuthorizationEncryptionEncValuesSupported(): array |
|
264 | { |
||
265 | 1 | return $this->metadata['authorization_encryption_enc_values_supported'] ?? []; |
|
266 | } |
||
267 | |||
268 | 1 | public function getIntrospectionEndpoint(): ?string |
|
269 | { |
||
270 | 1 | return $this->metadata['introspection_endpoint'] ?? null; |
|
271 | } |
||
272 | |||
273 | 1 | public function getIntrospectionEndpointAuthMethodsSupported(): array |
|
274 | { |
||
275 | 1 | return $this->metadata['introspection_endpoint_auth_methods_supported'] ?? []; |
|
276 | } |
||
277 | |||
278 | 1 | public function getIntrospectionEndpointAuthSigningAlgValuesSupported(): array |
|
279 | { |
||
280 | 1 | return $this->metadata['introspection_endpoint_auth_signing_alg_values_supported'] ?? []; |
|
281 | } |
||
282 | |||
283 | 1 | public function getIntrospectionSigningAlgValuesSupported(): array |
|
284 | { |
||
285 | 1 | return $this->metadata['introspection_signing_alg_values_supported'] ?? []; |
|
286 | } |
||
287 | |||
288 | 1 | public function getIntrospectionEncryptionAlgValuesSupported(): array |
|
289 | { |
||
290 | 1 | return $this->metadata['introspection_encryption_alg_values_supported'] ?? []; |
|
291 | } |
||
292 | |||
293 | 1 | public function getIntrospectionEncryptionEncValuesSupported(): array |
|
294 | { |
||
295 | 1 | return $this->metadata['introspection_encryption_enc_values_supported'] ?? []; |
|
296 | } |
||
297 | |||
298 | 1 | public function getRequestObjectSigningAlgValuesSupported(): array |
|
299 | { |
||
300 | /** @var list<non-empty-string> $default */ |
||
301 | 1 | $default = ['none', 'RS256']; |
|
302 | |||
303 | 1 | return $this->metadata['request_object_signing_alg_values_supported'] ?? $default; |
|
0 ignored issues
–
show
|
|||
304 | } |
||
305 | |||
306 | 1 | public function getRequestObjectEncryptionAlgValuesSupported(): array |
|
307 | { |
||
308 | 1 | return $this->metadata['request_object_encryption_alg_values_supported'] ?? []; |
|
309 | } |
||
310 | |||
311 | 1 | public function getRequestObjectEncryptionEncValuesSupported(): array |
|
312 | { |
||
313 | 1 | return $this->metadata['request_object_encryption_enc_values_supported'] ?? []; |
|
314 | } |
||
315 | |||
316 | 1 | public function getRevocationEndpoint(): ?string |
|
317 | { |
||
318 | 1 | return $this->metadata['revocation_endpoint'] ?? null; |
|
319 | } |
||
320 | |||
321 | 1 | public function getRevocationEndpointAuthMethodsSupported(): array |
|
322 | { |
||
323 | 1 | return $this->metadata['revocation_endpoint_auth_methods_supported'] ?? []; |
|
324 | } |
||
325 | |||
326 | 1 | public function getRevocationEndpointAuthSigningAlgValuesSupported(): array |
|
327 | { |
||
328 | 1 | return $this->metadata['revocation_endpoint_auth_signing_alg_values_supported'] ?? []; |
|
329 | } |
||
330 | |||
331 | 1 | public function getCheckSessionIframe(): ?string |
|
332 | { |
||
333 | 1 | return $this->metadata['check_session_iframe'] ?? null; |
|
334 | } |
||
335 | |||
336 | 1 | public function getEndSessionIframe(): ?string |
|
337 | { |
||
338 | 1 | return $this->metadata['end_session_iframe'] ?? null; |
|
339 | } |
||
340 | |||
341 | 2 | public function isFrontchannelLogoutSupported(): bool |
|
342 | { |
||
343 | 2 | return $this->metadata['frontchannel_logout_supported'] ?? false; |
|
344 | } |
||
345 | |||
346 | 2 | public function isFrontchannelLogoutSessionSupported(): bool |
|
347 | { |
||
348 | 2 | return $this->metadata['frontchannel_logout_session_supported'] ?? false; |
|
349 | } |
||
350 | |||
351 | 2 | public function isBackchannelLogoutSupported(): bool |
|
352 | { |
||
353 | 2 | return $this->metadata['backchannel_logout_supported'] ?? false; |
|
354 | } |
||
355 | |||
356 | 2 | public function isBackchannelLogoutSessionSupported(): bool |
|
357 | { |
||
358 | 2 | return $this->metadata['backchannel_logout_session_supported'] ?? false; |
|
359 | } |
||
360 | |||
361 | 2 | public function isTlsClientCertificateBoundAccessTokens(): bool |
|
362 | { |
||
363 | 2 | return $this->metadata['tls_client_certificate_bound_access_tokens'] ?? false; |
|
364 | } |
||
365 | |||
366 | 1 | public function getMtlsEndpointAliases(): array |
|
367 | { |
||
368 | 1 | return $this->metadata['mtls_endpoint_aliases'] ?? []; |
|
369 | } |
||
370 | |||
371 | 1 | public function jsonSerialize(): array |
|
372 | { |
||
373 | 1 | return $this->metadata; |
|
374 | } |
||
375 | |||
376 | public function toArray(): array |
||
377 | { |
||
378 | return $this->metadata; |
||
379 | } |
||
380 | |||
381 | 1 | public function has(string $name): bool |
|
382 | { |
||
383 | 1 | return array_key_exists($name, $this->metadata); |
|
384 | } |
||
385 | |||
386 | 1 | public function get(string $name) |
|
387 | { |
||
388 | 1 | return $this->metadata[$name] ?? null; |
|
389 | } |
||
390 | } |
||
391 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..