2024-04-17 13:23:58 -04:00
< ? php
namespace BookStack\Access\Oidc ;
use Psr\Http\Message\ResponseInterface ;
class OidcUserinfoResponse implements ProvidesClaims
{
protected array $claims = [];
2024-04-19 09:12:27 -04:00
protected ? OidcJwtWithClaims $jwt = null ;
2024-04-17 13:23:58 -04:00
2024-04-19 09:12:27 -04:00
public function __construct ( ResponseInterface $response , string $issuer , array $keys )
2024-04-17 13:23:58 -04:00
{
2024-04-19 09:12:27 -04:00
$contentType = $response -> getHeader ( 'Content-Type' )[ 0 ];
if ( $contentType === 'application/json' ) {
2024-04-17 13:23:58 -04:00
$this -> claims = json_decode ( $response -> getBody () -> getContents (), true );
}
2024-04-19 09:12:27 -04:00
if ( $contentType === 'application/jwt' ) {
$this -> jwt = new OidcJwtWithClaims ( $response -> getBody () -> getContents (), $issuer , $keys );
$this -> claims = $this -> jwt -> getAllClaims ();
}
2024-04-17 13:23:58 -04:00
}
/**
* @ throws OidcInvalidTokenException
*/
2024-04-19 11:43:51 -04:00
public function validate ( string $idTokenSub , string $clientId ) : bool
2024-04-17 13:23:58 -04:00
{
2024-04-19 09:12:27 -04:00
if ( ! is_null ( $this -> jwt )) {
2024-04-19 11:43:51 -04:00
$this -> jwt -> validateCommonTokenDetails ( $clientId );
2024-04-19 09:12:27 -04:00
}
2024-04-17 13:23:58 -04:00
$sub = $this -> getClaim ( 'sub' );
// Spec: v1.0 5.3.2: The sub (subject) Claim MUST always be returned in the UserInfo Response.
if ( ! is_string ( $sub ) || empty ( $sub )) {
throw new OidcInvalidTokenException ( " No valid subject value found in userinfo data " );
}
// 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;
// if they do not match, the UserInfo Response values MUST NOT be used.
if ( $idTokenSub !== $sub ) {
throw new OidcInvalidTokenException ( " Subject value provided in the userinfo endpoint does not match the provided ID token value " );
}
2024-04-19 10:05:00 -04:00
// Spec v1.0 5.3.4 Defines the following:
// Verify that the OP that responded was the intended OP through a TLS server certificate check, per RFC 6125 [RFC6125].
// This is effectively done as part of the HTTP request we're making through CURLOPT_SSL_VERIFYHOST on the request.
// If the Client has provided a userinfo_encrypted_response_alg parameter during Registration, decrypt the UserInfo Response using the keys specified during Registration.
// We don't currently support JWT encryption for OIDC
// If the response was signed, the Client SHOULD validate the signature according to JWS [JWS].
// This is done as part of the validateCommonClaims above.
2024-04-17 13:23:58 -04:00
return true ;
}
public function getClaim ( string $claim ) : mixed
{
return $this -> claims [ $claim ] ? ? null ;
}
public function getAllClaims () : array
{
return $this -> claims ;
}
}