Started on a custom oidc oauth provider

This commit is contained in:
Dan Brown 2021-10-10 19:14:08 +01:00
parent 41438adbd1
commit 8ce696dff6
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
2 changed files with 124 additions and 16 deletions

View File

@ -0,0 +1,109 @@
<?php
namespace BookStack\Auth\Access;
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 OpenIdConnectOAuthProvider extends AbstractProvider
{
use BearerAuthorizationTrait;
/**
* @var string
*/
protected $authorizationEndpoint;
/**
* @var string
*/
protected $tokenEndpoint;
/**
* 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 '';
}
/**
* 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 ['openid', 'profile', 'email'];
}
/**
* 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
* @param array|string $data Parsed response data
* @return void
* @throws IdentityProviderException
*/
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.
*
* @param array $response
* @param AccessToken $token
* @return ResourceOwnerInterface
*/
protected function createResourceOwner(array $response, AccessToken $token)
{
return new GenericResourceOwner($response, '');
}
}

View File

@ -6,10 +6,8 @@ use BookStack\Exceptions\OpenIdConnectException;
use BookStack\Exceptions\StoppedAuthenticationException; use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException; use BookStack\Exceptions\UserRegistrationException;
use Exception; use Exception;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Token; use Lcobucci\JWT\Token;
use OpenIDConnectClient\AccessToken; use League\OAuth2\Client\Token\AccessToken;
use OpenIDConnectClient\OpenIDConnectProvider;
/** /**
* Class OpenIdConnectService * Class OpenIdConnectService
@ -66,27 +64,18 @@ class OpenIdConnectService
/** /**
* Load the underlying OpenID Connect Provider. * Load the underlying OpenID Connect Provider.
*/ */
protected function getProvider(): OpenIDConnectProvider protected function getProvider(): OpenIdConnectOAuthProvider
{ {
// Setup settings // Setup settings
$settings = [ $settings = [
'clientId' => $this->config['client_id'], 'clientId' => $this->config['client_id'],
'clientSecret' => $this->config['client_secret'], 'clientSecret' => $this->config['client_secret'],
'idTokenIssuer' => $this->config['issuer'],
'redirectUri' => url('/oidc/redirect'), 'redirectUri' => url('/oidc/redirect'),
'urlAuthorize' => $this->config['authorization_endpoint'], 'authorizationEndpoint' => $this->config['authorization_endpoint'],
'urlAccessToken' => $this->config['token_endpoint'], 'tokenEndpoint' => $this->config['token_endpoint'],
'urlResourceOwnerDetails' => null,
'publicKey' => $this->config['jwt_public_key'],
'scopes' => 'profile email',
]; ];
// Setup services return new OpenIdConnectOAuthProvider($settings);
$services = [
'signer' => new Sha256(),
];
return new OpenIDConnectProvider($settings, $services);
} }
/** /**
@ -135,6 +124,16 @@ class OpenIdConnectService
*/ */
protected function processAccessTokenCallback(AccessToken $accessToken): User protected function processAccessTokenCallback(AccessToken $accessToken): User
{ {
dd($accessToken->getValues());
// TODO - Create a class to manage token parsing and validation on this
// Using the config params:
// $this->config['jwt_public_key']
// $this->config['issuer']
//
// Ensure ID token validation is done:
// https://openid.net/specs/openid-connect-basic-1_0.html#IDTokenValidation
// To full affect and tested
$userDetails = $this->getUserDetails($accessToken->getIdToken()); $userDetails = $this->getUserDetails($accessToken->getIdToken());
$isLoggedIn = auth()->check(); $isLoggedIn = auth()->check();