Browse Source

Finished refactor/reorg around authkit2 lib as entrypoint

master
Adam Pippin 3 years ago
parent
commit
b72495523f
  1. 71
      src/Authkit2.php
  2. 2
      src/Http/Controllers/AuthenticationController.php
  3. 35
      src/Observers/UserObserver.php
  4. 8
      src/Oidc/Authentication/Authentication.php
  5. 19
      src/Oidc/Authentication/TokenAuthentication.php
  6. 216
      src/Oidc/Client.php
  7. 10
      src/Oidc/Flows/ServiceAccountFlow.php
  8. 46
      src/Oidc/Flows/UserFlow.php
  9. 194
      src/Oidc/Token.php
  10. 4
      src/Providers/Authkit2ServiceProvider.php
  11. 9
      src/Providers/AuthnServiceProvider.php

71
src/Authkit2.php

@ -11,6 +11,10 @@ namespace authkit2;
* @method static void cache_set(string $key, mixed $value)
* @method static mixed session_get(string $key)
* @method static void session_set(string $key, mixed $value)
* @method static void configure(string $client_id, string $client_secret, string $endpoint)
* @method static Oidc\Client get_client()
* @method static Oidc\Token get_token(string $access_token, ?string $refresh_token = null)
* @method static Oidc\Token refresh_token(Oidc\Token $token)
*/
class Authkit2
{
@ -23,11 +27,16 @@ class Authkit2
/**
* Functions this class provides
*
* @array<string,callable>
*/
protected $callbacks = [];
/**
* Oidc client with the application credentials
* @var \authkit2\Oidc\Client
*/
protected $client;
/**
* Try and detect if we recognize the environment the library is running
* in and adjust our implementations accordingly.
@ -38,14 +47,16 @@ class Authkit2
*/
protected function __construct()
{
$callbacks = $this->getCommonCallbacks();
if (defined('LARAVEL_START'))
{
$this->initializeLaravel();
$callbacks = array_merge($callbacks, $this->getLaravelCallbacks());
}
else
{
$this->initializeNative();
$callbacks = array_merge($callbacks, $this->getNativeCallbacks());
}
$this->callbacks = $callbacks;
}
/**
@ -126,20 +137,36 @@ class Authkit2
return $value;
}
/**
* Initialize common library functions that don't require an environment-specific
* implementation
*
* @return array<string,callable>
*/
protected function getCommonCallbacks(): array
{
return [
'cache' => [$this, 'cache_helper'],
'configure' => [$this, 'ak2_configure'],
'get_client' => [$this, 'ak2_get_client'],
'get_token' => [$this, 'ak2_get_token'],
'refresh_token' => [$this, 'ak2_refresh_token']
];
}
/**
* Initialize the class by binding all the PHP native implementations of
* functions
*
* @return void
* @return array<string,callable>
*/
protected function initializeNative(): void
protected function getNativeCallbacks(): array
{
$this->callbacks = [
return [
'session_get' => [$this, 'native_session_get'],
'session_set' => [$this, 'native_session_set'],
'cache_get' => [$this, 'native_cache_get'],
'cache_set' => [$this, 'native_cache_set'],
'cache' => [$this, 'cache_helper']
'cache_set' => [$this, 'native_cache_set']
];
}
@ -147,16 +174,15 @@ class Authkit2
* Initialize the class by binding Laravel adapters as the implementation
* of all functions
*
* @return void
* @return array<string,callable>
*/
protected function initializeLaravel(): void
protected function getLaravelCallbacks(): array
{
$this->callbacks = [
return [
'session_get' => function(string $key) { return \Session::get($key); },
'session_set' => function(string $key, $value) { \Session::put($key, $value); },
'cache_get' => function(string $key) { return \Cache::get($key); },
'cache_set' => function(string $key, $value) { \Cache::set($key, $value); },
'cache' => [$this, 'cache_helper']
'cache_set' => function(string $key, $value) { \Cache::set($key, $value); }
];
}
@ -224,5 +250,24 @@ class Authkit2
{
}
protected function ak2_configure(string $client_id, string $client_secret, string $endpoint): void
{
$this->client = new \authkit2\Oidc\Client($endpoint, $client_id, $client_secret);
}
protected function ak2_get_client(): Oidc\Client
{
return $this->client;
}
protected function ak2_get_token(string $access_token, ?string $refresh_token = null): Oidc\Token
{
return Oidc\Token::fromString($this->client, $access_token, $refresh_token);
}
protected function ak2_refresh_token(Oidc\Token $token): Token
{
return $this->client->refreshToken($token);
}
}

2
src/Http/Controllers/AuthenticationController.php

@ -53,7 +53,7 @@ class AuthenticationController extends Controller
// TODO: Check for error response
// Exchange the code for a token
$token = $this->user_flow->exchangeCodeForToken(config('authkit.authn.openid.redirect_uri'), $request->code);
$token = $this->user_flow->exchangeCodeForToken($request->code, config('authkit.authn.openid.redirect_uri'));
$user_info = $token->getUserInfo();
// Try and use the token to find the local user

35
src/Observers/UserObserver.php

@ -1,6 +1,7 @@
<?php
namespace authkit2\Observers;
use authkit2\Authkit2;
class UserObserver
{
@ -8,8 +9,11 @@ class UserObserver
'saving', 'saved', 'restoring', 'restored', 'replicating',
'deleting', 'deleted', 'forceDeleted',*/
protected static $token_cache = [];
public function retrieved($user)
{
// Grab the token and refresh off of the user
if ($user instanceof \authkit2\Models\IAuthkitUser)
{
$token = $user->{$user->getAccessTokenName()};
@ -21,14 +25,37 @@ class UserObserver
$refresh = $user->authkit_refresh_token;
}
$user->authkit = \authkit2\Oidc\Token::fromString($token, $refresh);
// TODO: If access_token is expired, try refresh
// If refresh_token is expired, ?!!
// \Illuminate\Auth\Access\UnauthorizedException
// Create a token object
$user->authkit = Authkit2::get_token($token, $refresh);
// Set a refresh callback on the token -- when it's been refreshed,
// then set the new tokens on the user and save it
$user->authkit->setRefreshCallback(function($token) use ($user) {
if ($user instanceof \authkit2\Models\IAuthkitUser)
{
$user->{$user->getAccessTokenName()} = $token->getAccessToken();
$user->{$user->getRefreshTokenName()} = $token->getRefreshToken();
}
else
{
$user->authkit_access_token = $token->getAccessToken();
$user->authkit_refresh_token = $token->getRefreshToken();
}
$user->save();
});
}
public function saving($user)
{
if (isset($user->authkit))
static::$token_cache[$user->authkit->getAccessToken()] = $user->authkit;
unset($user->authkit);
}
public function saved($user)
{
$access_token = ($user instanceof \authkit2\Models\IAuthkitUser) ? $user->{$user->getAccessTokenName()} : $user->authkit_access_token;
if (isset(static::$token_cache[$access_token]))
$user->authkit = static::$token_cache[$access_token];
}
}

8
src/Oidc/Authentication/Authentication.php

@ -33,4 +33,12 @@ abstract class Authentication
};
};
}
public function getClient(array $options = []): \GuzzleHttp\Client
{
$stack = new \GuzzleHttp\HandlerStack();
$stack->setHandler(new \GuzzleHttp\Handler\CurlHandler());
$stack->push($this->getMiddleware());
return new \GuzzleHttp\Client(array_merge($options, ['handler' => $stack]));
}
}

19
src/Oidc/Authentication/TokenAuthentication.php

@ -15,14 +15,26 @@ class TokenAuthentication extends Authentication
*/
protected $token;
/**
* Who to call if the token is expired
* @var callable
*/
protected $refresh_callback;
/**
* Create a new token authentication provider
*
* @param Token $token token to authenticate requests with
*/
public function __construct(Token $token)
public function __construct(Token $token, callable $refreshCallback = null)
{
$this->token = $token;
$this->refresh_callback = $refreshCallback;
}
public function setRefreshCallback(callable $refreshCallback): void
{
$this->refresh_callback = $refreshCallback;
}
/**
@ -35,6 +47,11 @@ class TokenAuthentication extends Authentication
*/
public function authenticate(\GuzzleHttp\Psr7\Request $request): \GuzzleHttp\Psr7\Request
{
if ($this->token->isExpired() && isset($this->refresh_callback))
{
$callback = $this->refresh_callback;
$this->token = $callback($this);
}
return $request->withHeader('Authorization', 'Bearer '.$this->token->getAccessToken());
}
}

216
src/Oidc/Client.php

@ -21,44 +21,53 @@ class Client
*/
protected $client;
/**
* OAuth client id
* @var string
*/
protected $client_id;
/**
* Base url of the OIDC realm
* @var string
*/
static $oidc_url;
protected $oidc_url;
/**
* OIDC config fetched from the server or restored from cache
* @var array<string,mixed>
*/
static $oidc_config;
protected $oidc_config;
/**
* Create a new OIDC client using the passed authentication provider
* Keys for validating signed JWT tokens
* @var array<string,mixed>
*/
protected $oidc_jwks;
/**
* Create a new OIDC client using the passed in client credentials
*
* @param Authentication\Authentication $auth
* @param string $url
* @param string $client_id
* @param string $client_secret
*/
public function __construct(Authentication\Authentication $auth)
public function __construct(string $url, string $client_id, string $client_secret)
{
$this->auth = $auth;
$this->auth = new Authentication\ClientAuthentication($client_id, $client_secret);
$this->client = $this->auth->getClient();
$this->oidc_url = $url;
$this->oidc_config = null;
$this->client_id = $client_id;
}
/**
* Retrieve a HTTP client containing our authentication middleware
*
* Constructed on first use
*
* @return \GuzzleHttp\Client
*/
public function getClient(): \GuzzleHttp\Client
{
if (!isset($this->client))
{
$stack = new \GuzzleHttp\HandlerStack();
$stack->setHandler(new \GuzzleHttp\Handler\CurlHandler());
$stack->push($this->auth->getMiddleware());
$this->client = new \GuzzleHttp\Client(['handler' => $stack]);
}
return $this->client;
}
@ -67,101 +76,79 @@ class Client
*
* @return ?string
*/
public static function getUrl(): ?string
public function getUrl(): string
{
return static::$oidc_url;
return $this->oidc_url;
}
/**
* Configure the library with a OpenId Connect realm url
* Get the OpenId Connect configuration
*
* @param string $url
* @return void
* @return array
*/
public static function setUrl(string $url): void
public function getConfiguration(): array
{
static::$oidc_url = $url;
}
if (!isset($this->oidc_config))
{
$url = $this->oidc_url;
$this->oidc_config = Authkit2::cache('oidc.config.'.md5($this->oidc_url), function() use ($url) {
$response = (new \GuzzleHttp\Client())->get($url.'/.well-known/openid-configuration');
return json_decode($response->getBody(), true);
});
/**
* Set the OpenId Connect configuration
*
* This is provided to allow external caching rather than having us refetch
* the configuration on every invocation of the project.
*
* @param array $config config as retrieved from getOidcConfig()
* @return void
*/
public static function setOidcConfig(array $config): void
{
static::$oidc_config = $config;
}
return $this->oidc_config;
}
/**
* Get the OpenId Connect configuration
* Get the web key set for verifying JWTs
*
* If not restored/set via setOidcConfig, this will be fetched from the OIDC
* realm on first use
*
* @return array
* @return array<string,array>
*/
public static function getOidcConfig(): array
public function getJsonWebKeySet(): array
{
if (!isset(static::$oidc_config))
if (!isset($this->oidc_jwks))
{
static::$oidc_config = Authkit2::cache('oidc.config', function() {
$response = (new \GuzzleHttp\Client())->get(static::$oidc_url.'/.well-known/openid-configuration');
return json_decode($response->getBody(), true);
$client = $this;
$this->oidc_jwks = Authkit2::cache('oidc.config.'.md5($this->oidc_url).'.jwks', function() use ($client) {
$response = $client->get($client->getConfiguration()['jwks_uri']);
return json_decode(json_encode($response), true);
});
}
return static::$oidc_config;
return $this->oidc_jwks;
}
/**
* Fetch a specific OpenId Connect endpoint from the configuration
* Get the signing algorithms for signing JWTs
*
* @param string $endpoint_name
* @return string
* @return string[]
*/
public function getEndpointUrl(string $endpoint_name): string
public function getTokenSigningAlgorithms(): array
{
return static::getOidcConfig()[$endpoint_name.'_endpoint'];
return $this->getConfiguration()['id_token_signing_alg_values_supported'];
}
/**
* Determine the final URL to make a request to given an arbitrarily-defined
* 'endpoint'.
*
* If the passed in value is a valid URI, it will be used directly. Otherwise,
* we will attempt to find a configured endpoint with a name matching the
* passed in value in the OIDC config.
* Fetch a specific OpenId Connect endpoint from the configuration
*
* @param string $endpoint url or endpoint name
* @return string url to call
* @param string $endpoint_name
* @return string
*/
protected function parseEndpoint(string $endpoint): string
public function getEndpointUrl(string $endpoint_name): string
{
if (filter_var($endpoint, \FILTER_VALIDATE_URL))
{
return $endpoint;
}
else
{
return $this->getEndpointUrl($endpoint);
}
return $this->getConfiguration()[$endpoint_name.'_endpoint'];
}
/**
* Make a HTTP get request to a OIDC endpoint or other URL
*
* @param string $endpoint url or endpoint name
* @param string $url
* @param array<string,scalar> $params query string parameters
* @return object json decoded response
*/
public function get(string $endpoint, array $params = []): object
protected function get(string $url, array $params = []): object
{
$response = $this->getClient()->get($this->parseEndpoint($endpoint), [
$response = $this->getClient()->get($url, [
'query' => $params
]);
return json_decode($response->getBody());
@ -173,15 +160,94 @@ class Client
* If form parameters are provided the request is sent as
* application/x-www-form-urlencoded
*
* @param string $endpoint url or endpoint name
* @param string $url
* @param array<string,scalar> $params form fields
* @return object json decoded response
*/
public function post(string $endpoint, array $params = []): object
protected function post(string $url, array $params = []): object
{
$response = $this->getClient()->post($this->parseEndpoint($endpoint), [
$response = $this->getClient()->post($url, [
'form_params' => $params
]);
return json_decode($response->getBody());
}
/**
* Create a 'service account' token tied to this client's id
*
* @return Token
*/
public function createTokenFromClient(): Token
{
$response = $this->post($this->getEndpointUrl('token'), [
'grant_type' => 'client_credentials'
]);
return Token::fromResponse($this, $response);
}
/**
* Convert a returned authorization code from the three legged flow
* into a token
*
* @param string $code
* @param string $redirect_uri
* @return Token
*/
public function createTokenFromAuthorizationCode(string $code, string $redirect_uri): Token
{
$response = $this->post($this->getEndpointUrl('token'), [
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => $redirect_uri
]);
// todo: check for response->error, response->error_description
return Token::fromResponse($this, $response);
}
/**
* Create a new access token from a refresh token
*
* @param string $refresh_token
* @return Token
*/
public function createTokenFromRefreshToken(string $refresh_token): Token
{
$response = $this->post($this->getEndpointUrl('token'), [
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token
]);
return Token::fromResponse($this, $response);
}
public function createAuthorizationRedirectUrl(string $redirect_uri, array $scopes, string $state): string
{
return $this->getEndpointUrl('authorization').'?'.http_build_query([
'client_id' => $this->client_id,
'redirect_uri' => $redirect_uri,
'scope' => implode(',', $scopes),
'response_type' => 'code',
'state' => $state
]);
}
public function createLogoutUrl(string $redirect_uri): string
{
return $this->getEndpointUrl('end_session').'?'.http_build_query([
'redirect_uri' => $redirect_uri
]);
}
public function refreshToken(Token $token): Token
{
return $this->createTokenFromRefreshToken($token->getRefreshToken());
}
public function getTokenUserInfo(Token $token): array
{
return json_decode($token->getClient()->get($this->getEndpointUrl('userinfo'))->getBody(), true);
}
// todo: introspect, etc
}

10
src/Oidc/Flows/ServiceAccountFlow.php

@ -19,12 +19,11 @@ class ServiceAccountFlow
/**
* Initialize a new service account flow
*
* @param string $client_id oauth client id
* @param string $client_secret oauth client secret
* @param Client $client
*/
public function __construct(string $client_id, string $client_secret)
public function __construct(Client $client)
{
$this->client = new Client(new ClientAuthentication($client_id, $client_secret));
$this->client = $client;
}
/**
@ -34,8 +33,7 @@ class ServiceAccountFlow
*/
public function getServiceAccountToken(): Token
{
$response = $this->client->post('token', ['grant_type'=>'client_credentials']);
return Token::fromResponse($response);
return $this->client->createTokenFromClient();
}
}

46
src/Oidc/Flows/UserFlow.php

@ -12,32 +12,19 @@ use authkit2\Oidc\Token;
class UserFlow
{
/**
* OIDC client authenticating as the client
* OIDC client
* @var Client
*/
protected $client;
/**
* oauth client id
* @var string
*/
protected $client_id;
/**
* oauth client secret
* @var string
*/
protected $client_secret;
/**
* Initialize a new user login flow
*
* @param string $client_id oauth client id
* @param string $client_secret oauth client secret
* @param Client $client
*/
public function __construct(string $client_id, string $client_secret)
public function __construct(Client $client)
{
$this->client_id = $client_id;
$this->client_secret = $client_secret;
$this->client = new Client(new ClientAuthentication($client_id, $client_secret));
$this->client = $client;
}
/**
@ -57,14 +44,7 @@ class UserFlow
$states = Authkit2::session_get('userflow.state') ?? [];
array_push($states, $state);
Authkit2::session_set('userflow.state', $states);
return $this->client->getEndpointUrl('authorization').'?'.http_build_query([
'client_id' => $this->client_id,
'redirect_uri' => $redirect_uri,
'scope' => implode(',', $scopes),
'response_type' => 'code',
'state' => $state
]);
return $this->client->createAuthorizationRedirectUrl($redirect_uri, $scopes, $state);
}
/**
@ -92,19 +72,15 @@ class UserFlow
* After the user is redirected back with a authorization code, exchange it
* for an access token
*
* THIS DOES NOT VALIDATE THE STATE. Call validateState first.
*
* @param string $redirect_uri url the oidc endpoint redirects back to; must match one given in call to getRedirectUrl
* @param string $code code returned by the authorization flow
* @return Token
*/
public function exchangeCodeForToken(string $redirect_uri, string $code): Token
public function exchangeCodeForToken(string $code, string $redirect_uri): Token
{
$response = $this->client->post('token', [
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => $redirect_uri
]);
return Token::fromResponse($response);
return $this->client->createTokenFromAuthorizationCode($code, $redirect_uri);
}
/**
@ -116,9 +92,7 @@ class UserFlow
*/
public function getLogoutUrl(string $redirect_uri): string
{
return $this->client->getEndpointUrl('end_session').'?'.http_build_query([
'redirect_uri' => $redirect_uri
]);
return $this->client->createLogoutUrl($redirect_uri);
}
}

194
src/Oidc/Token.php

@ -12,16 +12,8 @@ use Firebase\JWT\JWK;
class Token
{
/**
* If we check for an expired token and it expires within this many seconds
* from now, just go ahead and refresh it early
* @var int
*/
const EXPIRATION_GRACE_PERIOD = 60;
/**
* Http client we've initialized with our authentication middleware for this
* token in place
* @var \GuzzleHttp\Client
* OIDC client
* @var Client
*/
protected $client = null;
@ -41,13 +33,25 @@ class Token
* Cache of userinfo endpoint response
* @var array<string,scalar>
*/
protected $userinfo = null;
protected $user_info = null;
/**
* Decoded access token JWT data
* @var array<string,mixed>
*/
protected $access_token_data = null;
/**
* Cache of decoded JWT token
* Decoded refresh token JWT data
* @var array<string,mixed>
*/
protected $token_data = null;
protected $refresh_token_data = null;
/**
* Callback to be notified when this token is refreshed
* @var callable
*/
protected $refresh_callback;
/**
* Initialize token with the from*() static methods
@ -60,76 +64,167 @@ class Token
* Create a token given a access_token and optionally refresh_token, passed
* as a string
*
* @param Client $client
* @param string $access_token
* @param ?string $refresh_token
* @return Token
*/
public static function fromString(string $access_token, ?string $refresh_token = null): Token
public static function fromString(Client $client, string $access_token, ?string $refresh_token = null): Token
{
$token = new Token();
$token->client = $client;
$token->access_token = $access_token;
$token->refresh_token = $refresh_token;
return $token;
}
/**
* Get a HTTP client that's authenticated with this token's credentials
*
* @param array $options
* @return \GuzzleHttp\Client
*/
public function getClient(array $options = []): \GuzzleHttp\Client
{
// Create the token auth implementation; this holds a callback to the token
// to ask it to refresh itself
$state = new \stdClass();
$state->refresher = function($token) use ($state) {
$client = $this->client;
$refresh_callback = $this->refresh_callback;
// Refresh the token
$new_token = $client->createTokenFromRefreshToken($this->refresh_token);
// Rebind this callback to the new token
$state->refresher->bindTo($new_token);
// Call the refresh callback
if (isset($refresh_callback))
{
// Copy over the token-level refresh callback
$new_token->setRefreshCallback($refresh_callback);
$refresh_callback($new_token);
}
return $new_token;
};
$auth = new Authentication\TokenAuthentication($this, $state->refresher);
return $auth->getClient($options);
}
/**
* Callback to notify when this token is refreshed
*
* @param callable $callback
* @return void
*/
public function setRefreshCallback(callable $callback): void
{
$this->refresh_callback = $callback;
}
/**
* Create a token from a OIDC response from the token endpoint
*
* @param Client $client
* @param object $response
* @return Token
*/
public static function fromResponse(object $response): Token
public static function fromResponse(Client $client, object $response): Token
{
$token = new Token();
$token->client = $client;
$token->access_token = $response->access_token ?? null;
$token->access_token_expires_at = isset($response->expires_in) ? time() + $response->expires_in : null;
$token->refresh_token = $response->refresh_token ?? null;
$token->refresh_token_expires_at = isset($response->refresh_expires_in) ? time() + $response->refresh_expires_in : null;
return $token;
}
/**
* Fetch an oidc client authenticated with this token
* Fetch the raw decoded data out of our JWT access token
*
* @return Client
* @return array<string,mixed>
*/
public function getClient(): Client
public function getAccessTokenData(): array
{
if (!isset($this->client))
if (!isset($this->access_token_data))
{
$this->client = new Client(new Authentication\TokenAuthentication($this));
$this->access_token_data = json_decode(json_encode($this->decode($this->access_token)), true);
}
return $this->client;
return $this->access_token_data;
}
/**
* Refresh the access token
* Fetch the raw decoded data out of our JWT refresh token
*
* @return void
* @return array<string,mixed>
*/
public function refresh()
public function getRefreshTokenData(): array
{
if (!isset($this->refresh_token_data))
{
if (!isset($this->refresh_token))
{
throw new \UnexpectedValueException("Refresh token not set!");
}
$this->refresh_token_data = json_decode(json_encode($this->decode($this->refresh_token)), true);
}
return $this->token_data;
}
/**
* Fetch the raw decoded data out of our JWT access token
* Decode a token as a JWT token
*
* @return array<string,mixed>
* @param string $token
* @return object
*/
protected function decode(string $token): object
{
return JWT::decode($token, JWK::parseKeySet($this->client->getJsonWebKeySet()), $this->client->getTokenSigningAlgorithms());
}
/**
* Check whether the token is valid -- that is, whether you could actually
* use it for things.
*
* To be considered valid, the access token must be parseable and signed by
* the correct keys but _may_ be expired. The refresh token must be parseable,
* signed by the correct key, and may not be expired.
*
* @return bool
*/
public function getTokenData(): array
public function isValid(): bool
{
if (!isset($this->token_data))
try
{
$this->token_data = json_decode(json_encode($this->decode()), true);
$this->getAccessTokenData();
return true;
}
catch (\UnexpectedValueException $ex)
{
if ($ex instanceof \Firebase\JWT\ExpiredException)
{
try
{
$this->getRefreshTokenData();
return true;
}
catch (\UnexpectedValueException $ex)
{
return false;
}
}
return false;
}
return $this->token_data;
}
/**
* Check whether the access token is expired
*
* If we fail to parse it because it's expired, or the expiration time is
* within EXPIRATION_GRACE_PERIOD seconds of now, we consider it expired.
* As long as the refresh token is valid, this is recoverly by calling
* passing this token to refresh on the client.
*
* @return bool
*/
@ -137,31 +232,25 @@ class Token
{
try
{
$data = $this->getTokenData();
$token_data = $this->getAccessTokenData();
if ($token_data['exp'] <= time())
return true;
return false;
}
catch (\Firebase\JWT\ExpiredException $ex)
{
return true;
}
if ($data['exp'] <= time() - static::EXPIRATION_GRACE_PERIOD)
return true;
else
return false;
}
/**
* Decode the access token as a JWT token
* Check whether this token needs a refresh to be used
*
* @return object
* @return bool
*/
protected function decode(): object
public function needsRefresh(): bool
{
$client = $this->getClient();
$jwks = Authkit2::cache('oidc.jwks', function() use ($client) {
$response = $client->get(Client::getOidcConfig()['jwks_uri']);
return json_decode(json_encode($response), true);
});
return JWT::decode($this->access_token, JWK::parseKeySet($jwks), Client::getOidcConfig()['id_token_signing_alg_values_supported']);
return $this->isValid() && $this->isExpired() && isset($this->refresh_token);
}
/**
@ -192,12 +281,7 @@ class Token
*/
public function getUserInfo(): array
{
if (!isset($this->userinfo))
{
$this->userinfo = json_decode(json_encode($this->getClient()->get('userinfo')), true);
}
return $this->userinfo;
return $this->client->getTokenUserInfo($this);
}
/**
@ -217,7 +301,7 @@ class Token
*/
public function getUserId(): string
{
return 'crn:user:'.$this->getTokenData()['sub'];
return 'crn:user:'.$this->getAccessTokenData()['sub'];
}
}

4
src/Providers/Authkit2ServiceProvider.php

@ -48,10 +48,6 @@ class Authkit2ServiceProvider extends ServiceProvider
__DIR__.'/../../database/migrations/existing/authkit2_users_update_minimal.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_users_update_minimal.php')
], 'migrations_existing');
}
$this->app->booted(function($app) {
\authkit2\Oidc\Client::setUrl(config('authkit.authn.openid.endpoint'));
});
}
}

9
src/Providers/AuthnServiceProvider.php

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace authkit2\Providers;
use Illuminate\Support\ServiceProvider;
use \authkit2\Authkit2;
/**
* Authentication provider to perform setup for authentication processes
@ -19,10 +20,10 @@ class AuthnServiceProvider extends ServiceProvider
public function register(): void
{
$this->app->singleton(\authkit2\Oidc\Flows\ServiceAccountFlow::class, function($app) {
return new \authkit2\Oidc\Flows\ServiceAccountFlow(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'));
return new \authkit2\Oidc\Flows\ServiceAccountFlow(Authkit2::get_client());
});
$this->app->singleton(\authkit2\Oidc\Flows\UserFlow::class, function($app) {
return new \authkit2\Oidc\Flows\UserFlow(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'));
return new \authkit2\Oidc\Flows\UserFlow(Authkit2::get_client());
});
}
@ -118,5 +119,9 @@ class AuthnServiceProvider extends ServiceProvider
'authkit.authn.openid.endpoint' => env('AUTHKIT_ENDPOINT', isset($config_json['auth-server-url']) && isset($config_json['realm']) ? $config_json['auth-server-url'].'realms/'.$config_json['realm'] : null)
]);
}
$this->app->booted(function($app) {
Authkit2::configure(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'), config('authkit.authn.openid.endpoint'));
});
}
}

Loading…
Cancel
Save