]> BookStack Code Mirror - bookstack/blob - app/Access/Oidc/OidcUserinfoResponse.php
7c7760434b0f6865b3e36e110548a318fca0178c
[bookstack] / app / Access / Oidc / OidcUserinfoResponse.php
1 <?php
2
3 namespace BookStack\Access\Oidc;
4
5 use Psr\Http\Message\ResponseInterface;
6
7 class OidcUserinfoResponse implements ProvidesClaims
8 {
9     protected array $claims = [];
10
11     public function __construct(ResponseInterface $response)
12     {
13         if ($response->getHeader('Content-Type')[0] === 'application/json') {
14             $this->claims = json_decode($response->getBody()->getContents(), true);
15         }
16
17         // TODO - Support JWTs
18         // TODO - Response validation (5.3.4):
19             // TODO - Verify that the OP that responded was the intended OP through a TLS server certificate check, per RFC 6125 [RFC6125].
20             // TODO - If the Client has provided a userinfo_encrypted_response_alg parameter during Registration, decrypt the UserInfo Response using the keys specified during Registration.
21             // TODO - If the response was signed, the Client SHOULD validate the signature according to JWS [JWS].
22     }
23
24     /**
25      * @throws OidcInvalidTokenException
26      */
27     public function validate(string $idTokenSub): bool
28     {
29         $sub = $this->getClaim('sub');
30
31         // Spec: v1.0 5.3.2: The sub (subject) Claim MUST always be returned in the UserInfo Response.
32         if (!is_string($sub) || empty($sub)) {
33             throw new OidcInvalidTokenException("No valid subject value found in userinfo data");
34         }
35
36         // Spec: v1.0 5.3.2: The sub Claim in the UserInfo Response MUST be verified to exactly match the sub Claim in the ID Token;
37         // if they do not match, the UserInfo Response values MUST NOT be used.
38         if ($idTokenSub !== $sub) {
39             throw new OidcInvalidTokenException("Subject value provided in the userinfo endpoint does not match the provided ID token value");
40         }
41
42         return true;
43     }
44
45     public function getClaim(string $claim): mixed
46     {
47         return $this->claims[$claim] ?? null;
48     }
49
50     public function getAllClaims(): array
51     {
52         return $this->claims;
53     }
54 }