128 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			128 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;
 | 
						|
    }
 | 
						|
}
 |