3e9e196cda
Related to #4734. Uses core logic from League AbstractProvider.
127 lines
3.6 KiB
PHP
127 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace BookStack\Access\Oidc;
|
|
|
|
use League\OAuth2\Client\Grant\AbstractGrant;
|
|
use League\OAuth2\Client\Provider\AbstractProvider;
|
|
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
|
use League\OAuth2\Client\Provider\GenericResourceOwner;
|
|
use League\OAuth2\Client\Provider\ResourceOwnerInterface;
|
|
use League\OAuth2\Client\Token\AccessToken;
|
|
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
/**
|
|
* Extended OAuth2Provider for using with OIDC.
|
|
* Credit to the https://github.com/steverhoades/oauth2-openid-connect-client
|
|
* project for the idea of extending a League\OAuth2 client for this use-case.
|
|
*/
|
|
class OidcOAuthProvider extends AbstractProvider
|
|
{
|
|
use BearerAuthorizationTrait;
|
|
|
|
protected string $authorizationEndpoint;
|
|
protected string $tokenEndpoint;
|
|
|
|
/**
|
|
* Scopes to use for the OIDC authorization call.
|
|
*/
|
|
protected array $scopes = ['openid', 'profile', 'email'];
|
|
|
|
/**
|
|
* Returns the base URL for authorizing a client.
|
|
*/
|
|
public function getBaseAuthorizationUrl(): string
|
|
{
|
|
return $this->authorizationEndpoint;
|
|
}
|
|
|
|
/**
|
|
* Returns the base URL for requesting an access token.
|
|
*/
|
|
public function getBaseAccessTokenUrl(array $params): string
|
|
{
|
|
return $this->tokenEndpoint;
|
|
}
|
|
|
|
/**
|
|
* Returns the URL for requesting the resource owner's details.
|
|
*/
|
|
public function getResourceOwnerDetailsUrl(AccessToken $token): string
|
|
{
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Add another scope to this provider upon the default.
|
|
*/
|
|
public function addScope(string $scope): void
|
|
{
|
|
$this->scopes[] = $scope;
|
|
$this->scopes = array_unique($this->scopes);
|
|
}
|
|
|
|
/**
|
|
* Returns the default scopes used by this provider.
|
|
*
|
|
* This should only be the scopes that are required to request the details
|
|
* of the resource owner, rather than all the available scopes.
|
|
*/
|
|
protected function getDefaultScopes(): array
|
|
{
|
|
return $this->scopes;
|
|
}
|
|
|
|
/**
|
|
* Returns the string that should be used to separate scopes when building
|
|
* the URL for requesting an access token.
|
|
*/
|
|
protected function getScopeSeparator(): string
|
|
{
|
|
return ' ';
|
|
}
|
|
|
|
/**
|
|
* Checks a provider response for errors.
|
|
* @throws IdentityProviderException
|
|
*/
|
|
protected function checkResponse(ResponseInterface $response, $data): void
|
|
{
|
|
if ($response->getStatusCode() >= 400 || isset($data['error'])) {
|
|
throw new IdentityProviderException(
|
|
$data['error'] ?? $response->getReasonPhrase(),
|
|
$response->getStatusCode(),
|
|
(string) $response->getBody()
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a resource owner object from a successful resource owner
|
|
* details request.
|
|
*/
|
|
protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface
|
|
{
|
|
return new GenericResourceOwner($response, '');
|
|
}
|
|
|
|
/**
|
|
* Creates an access token from a response.
|
|
*
|
|
* The grant that was used to fetch the response can be used to provide
|
|
* additional context.
|
|
*/
|
|
protected function createAccessToken(array $response, AbstractGrant $grant): OidcAccessToken
|
|
{
|
|
return new OidcAccessToken($response);
|
|
}
|
|
|
|
/**
|
|
* Get the method used for PKCE code verifier hashing, which is passed
|
|
* in the "code_challenge_method" parameter in the authorization request.
|
|
*/
|
|
protected function getPkceMethod(): string
|
|
{
|
|
return static::PKCE_METHOD_S256;
|
|
}
|
|
}
|