2021-10-11 02:14:08 +08:00
|
|
|
<?php
|
|
|
|
|
2021-10-13 06:04:28 +08:00
|
|
|
namespace BookStack\Auth\Access\Oidc;
|
2021-10-11 02:14:08 +08:00
|
|
|
|
2021-10-12 02:05:16 +08:00
|
|
|
use League\OAuth2\Client\Grant\AbstractGrant;
|
2021-10-11 02:14:08 +08:00
|
|
|
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.
|
|
|
|
*/
|
2021-10-13 06:04:28 +08:00
|
|
|
class OidcOAuthProvider extends AbstractProvider
|
2021-10-11 02:14:08 +08:00
|
|
|
{
|
|
|
|
use BearerAuthorizationTrait;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $authorizationEndpoint;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $tokenEndpoint;
|
|
|
|
|
2022-08-02 23:56:56 +08:00
|
|
|
/**
|
2022-08-30 00:46:41 +08:00
|
|
|
* Scopes to use for the OIDC authorization call.
|
2022-08-02 23:56:56 +08:00
|
|
|
*/
|
|
|
|
protected array $scopes = ['openid', 'profile', 'email'];
|
|
|
|
|
2021-10-11 02:14:08 +08:00
|
|
|
/**
|
|
|
|
* 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 '';
|
|
|
|
}
|
|
|
|
|
2022-08-02 23:56:56 +08:00
|
|
|
/**
|
|
|
|
* Add an additional scope to this provider upon the default.
|
|
|
|
*/
|
|
|
|
public function addScope(string $scope): void
|
|
|
|
{
|
|
|
|
$this->scopes[] = $scope;
|
|
|
|
$this->scopes = array_unique($this->scopes);
|
|
|
|
}
|
|
|
|
|
2021-10-11 02:14:08 +08:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
{
|
2022-08-02 23:56:56 +08:00
|
|
|
return $this->scopes;
|
2021-10-11 02:14:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @param ResponseInterface $response
|
2021-10-16 23:01:59 +08:00
|
|
|
* @param array|string $data Parsed response data
|
|
|
|
*
|
2021-10-11 02:14:08 +08:00
|
|
|
* @throws IdentityProviderException
|
2021-10-16 23:01:59 +08:00
|
|
|
*
|
|
|
|
* @return void
|
2021-10-11 02:14:08 +08:00
|
|
|
*/
|
|
|
|
protected function checkResponse(ResponseInterface $response, $data)
|
|
|
|
{
|
|
|
|
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.
|
|
|
|
*
|
2021-10-16 23:01:59 +08:00
|
|
|
* @param array $response
|
2021-10-11 02:14:08 +08:00
|
|
|
* @param AccessToken $token
|
2021-10-16 23:01:59 +08:00
|
|
|
*
|
2021-10-11 02:14:08 +08:00
|
|
|
* @return ResourceOwnerInterface
|
|
|
|
*/
|
|
|
|
protected function createResourceOwner(array $response, AccessToken $token)
|
|
|
|
{
|
|
|
|
return new GenericResourceOwner($response, '');
|
|
|
|
}
|
2021-10-12 02:05:16 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an access token from a response.
|
|
|
|
*
|
|
|
|
* The grant that was used to fetch the response can be used to provide
|
|
|
|
* additional context.
|
|
|
|
*
|
2021-10-16 23:01:59 +08:00
|
|
|
* @param array $response
|
2021-10-12 02:05:16 +08:00
|
|
|
* @param AbstractGrant $grant
|
2021-10-16 23:01:59 +08:00
|
|
|
*
|
2021-10-13 06:04:28 +08:00
|
|
|
* @return OidcAccessToken
|
2021-10-12 02:05:16 +08:00
|
|
|
*/
|
|
|
|
protected function createAccessToken(array $response, AbstractGrant $grant)
|
|
|
|
{
|
2021-10-13 06:04:28 +08:00
|
|
|
return new OidcAccessToken($response);
|
2021-10-12 02:05:16 +08:00
|
|
|
}
|
2021-10-16 23:01:59 +08:00
|
|
|
}
|