Browse Source

code formatter

master
Adam Pippin 3 years ago
parent
commit
4dbff7e0d3
  1. 1
      .php_cs.dist
  2. 2
      config/authkit.php
  3. 10
      examples/custom/_common.php
  4. 2
      examples/custom/_config.php
  5. 5
      examples/custom/callback.php
  6. 18
      examples/custom/index.php
  7. 5
      examples/custom/login.php
  8. 8
      examples/custom/logout.php
  9. 130
      src/Authkit2.php
  10. 6
      src/Events/UserEvent.php
  11. 8
      src/Events/UserInfoEvent.php
  12. 8
      src/Events/UserLogin.php
  13. 2
      src/Events/UserLogout.php
  14. 17
      src/Http/Controllers/AuthenticationController.php
  15. 2
      src/Http/Controllers/Controller.php
  16. 9
      src/Models/Token.php
  17. 22
      src/Observers/UserObserver.php
  18. 22
      src/Oidc/Authentication/Authentication.php
  19. 16
      src/Oidc/Authentication/ClientAuthentication.php
  20. 27
      src/Oidc/Authentication/TokenAuthentication.php
  21. 113
      src/Oidc/Client.php
  22. 13
      src/Oidc/Flows/ServiceAccountFlow.php
  23. 34
      src/Oidc/Flows/UserFlow.php
  24. 77
      src/Oidc/Token.php
  25. 8
      src/Providers/Authkit2ServiceProvider.php
  26. 16
      src/Providers/AuthnServiceProvider.php
  27. 6
      src/Providers/AuthzServiceProvider.php

1
.php_cs.dist

@ -2,6 +2,7 @@
$finder = Symfony\Component\Finder\Finder::create()
->exclude('bootstrap/cache')
->exclude('database')
->exclude('storage')
->exclude('vendor')
->in(__DIR__)

2
config/authkit.php

@ -15,7 +15,7 @@ return [
'enable' => true,
/**
* Scopes to request from the OIDC provider
* Scopes to request from the OIDC provider.
*/
'scopes' => ['email'],

10
examples/custom/_common.php

@ -1,7 +1,9 @@
<?php
require(__DIR__.'/vendor/autoload.php');
require(__DIR__.'/_config.php');
declare(strict_types=1);
require __DIR__.'/vendor/autoload.php';
require __DIR__.'/_config.php';
session_start();
@ -10,7 +12,7 @@ session_start();
function html_header()
{
return <<<EOT
return <<<'EOT'
<!DOCTYPE html>
<html lang="en">
<head>
@ -23,7 +25,7 @@ function html_header()
function html_footer()
{
return <<<EOT
return <<<'EOT'
</body>
</html>
EOT;

2
examples/custom/_config.php

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
define('OPENID_CLIENT_ID', 'test');
define('OPENID_CLIENT_SECRET', 'a0ee4936-ef77-4e4b-87f3-8b4a2706d53a');
define('OPENID_ENDPOINT', 'http://127.0.0.1:8080/auth/realms/Test');

5
examples/custom/callback.php

@ -1,6 +1,8 @@
<?php
require('_common.php');
declare(strict_types=1);
require '_common.php';
use authkit2\Authkit2;
@ -31,4 +33,3 @@ $_SESSION['refresh_token'] = $token->getRefreshToken();
// Now redirect them back to the home page!
header('Location: index.php');

18
examples/custom/index.php

@ -1,6 +1,8 @@
<?php
require('_common.php');
declare(strict_types=1);
require '_common.php';
use authkit2\Authkit2;
@ -11,21 +13,21 @@ if (isset($_SESSION['access_token']) && isset($_SESSION['refresh_token']))
$token = Authkit2::get_token($_SESSION['access_token'], $_SESSION['refresh_token']);
// If the token needs to be refreshed, the library will do that for us, but
// we need to set a callback so it can let us know to store the updated token.
$token->setRefreshCallback(function($token) {
echo "Refreshing token...<br>";
$token->setRefreshCallback(static function($token) {
echo 'Refreshing token...<br>';
$_SESSION['access_token'] = $token->getAccessToken();
$_SESSION['refresh_token'] = $token->getRefreshToken();
});
// Fetch the user's information from the openid provider
$user_info = $token->getUserInfo();
echo "Hello, ".$user_info['name']."!<br>";
echo "Your id is: ".$token->getUserId()."<br>";
echo "<a href=\"logout.php\">Logout</a><br>";
echo 'Hello, '.$user_info['name'].'!<br>';
echo 'Your id is: '.$token->getUserId().'<br>';
echo '<a href="logout.php">Logout</a><br>';
}
else
{
echo "Not signed in.<br>";
echo "<a href=\"login.php\">Login</a><br>";
echo 'Not signed in.<br>';
echo '<a href="login.php">Login</a><br>';
}
echo html_footer();

5
examples/custom/login.php

@ -1,6 +1,8 @@
<?php
require('_common.php');
declare(strict_types=1);
require '_common.php';
use authkit2\Authkit2;
@ -10,4 +12,3 @@ $flow = new \authkit2\Oidc\Flows\UserFlow(Authkit2::get_client());
// Step 1: Redirect the user to the OIDC provider for authentication
$redirect_url = $flow->getRedirectUrl(OPENID_CALLBACK_URL);
header('Location: '.$redirect_url);

8
examples/custom/logout.php

@ -1,6 +1,8 @@
<?php
require('_common.php');
declare(strict_types=1);
require '_common.php';
use authkit2\Authkit2;
@ -8,10 +10,8 @@ use authkit2\Authkit2;
$flow = new \authkit2\Oidc\Flows\UserFlow(Authkit2::get_client());
// Log the user out locally
unset($_SESSION['access_token']);
unset($_SESSION['refresh_token']);
unset($_SESSION['access_token'], $_SESSION['refresh_token']);
// Redirect them to the openid provider to log them out
$redirect_url = $flow->getLogoutUrl(OPENID_REDIRECT_URL);
header('Location: '.$redirect_url);

130
src/Authkit2.php

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace authkit2;
/**
@ -26,13 +28,13 @@ class Authkit2
private const LIB_PREFIX = 'authkit2.';
/**
* Functions this class provides
* Functions this class provides.
* @array<string,callable>
*/
protected $callbacks = [];
/**
* Oidc client with the application credentials
* Oidc client with the application credentials.
* @var \authkit2\Oidc\Client
*/
protected $client;
@ -43,7 +45,6 @@ class Authkit2
*
* Basically, if we see the LARAVEL_START constant we assume Laravel and
* use Laravel facades, otherwise we use native php implementations.
*
*/
protected function __construct()
{
@ -60,7 +61,7 @@ class Authkit2
}
/**
* Retrieve the instance of Authkit2 class
* Retrieve the instance of Authkit2 class.
*
* @return Authkit2
*/
@ -75,13 +76,13 @@ class Authkit2
}
/**
* Override any of the function implementations
* Override any of the function implementations.
*
* Name is the same as the callable function name, e.g.,
* Authkit2::cache_set() can be overriden with Authkit2->cache_set = function(...) {}
*
* @param string $name
* @param callable $value
* @param string $name
* @param callable $value
* @return void
*/
public function __set(string $name, $value): void
@ -101,10 +102,10 @@ class Authkit2
}
/**
* Call any of the provided methods
* Call any of the provided methods.
*
* @param string $name
* @param mixed[] $arguments
* @param string $name
* @param mixed[] $arguments
* @return mixed
*/
public static function __callStatic(string $name, array $arguments)
@ -122,8 +123,8 @@ class Authkit2
* Helper method for getting cache values, and generating and setting if
* they do not exist.
*
* @param string $key cache key
* @param callable $generator method that returns the value if we do not have it cached
* @param string $key cache key
* @param callable $generator method that returns the value if we do not have it cached
* @return mixed
*/
protected function cache_helper(string $key, callable $generator)
@ -139,7 +140,7 @@ class Authkit2
/**
* Initialize common library functions that don't require an environment-specific
* implementation
* implementation.
*
* @return array<string,callable>
*/
@ -156,7 +157,7 @@ class Authkit2
/**
* Initialize the class by binding all the PHP native implementations of
* functions
* functions.
*
* @return array<string,callable>
*/
@ -172,7 +173,7 @@ class Authkit2
/**
* Initialize the class by binding Laravel adapters as the implementation
* of all functions
* of all functions.
*
* @return array<string,callable>
*/
@ -180,35 +181,35 @@ class Authkit2
{
return [
'session_get' =>
/**
* Fetch a variable from the session
* @param string $key
* @return mixed
*/
function(string $key) { return \Session::get($key); },
/**
* Fetch a variable from the session.
* @param string $key
* @return mixed
*/
static function(string $key) { return \Session::get($key); },
'session_set' =>
/**
* Set a variable in the session
* @param string $key
* @param mixed $value
* @return void
*/
function(string $key, $value): void { \Session::put($key, $value); },
/**
* Set a variable in the session.
* @param string $key
* @param mixed $value
* @return void
*/
static function(string $key, $value): void { \Session::put($key, $value); },
'cache_get' =>
/**
* Fetch a value from cache
* @param string $key
* @return mixed
*/
function(string $key) { return \Cache::get($key); },
/**
* Fetch a value from cache.
* @param string $key
* @return mixed
*/
static function(string $key) { return \Cache::get($key); },
'cache_set' =>
/**
* Set a value in cache
* @param string $key
* @param mixed $value
* @return void
*/
function(string $key, $value): void { \Cache::set($key, $value); }
/**
* Set a value in cache.
* @param string $key
* @param mixed $value
* @return void
*/
static function(string $key, $value): void { \Cache::set($key, $value); }
];
}
@ -216,7 +217,7 @@ class Authkit2
* Retrieve a property out of the $_SESSION variable; null if the
* property doesn't exist.
*
* @param string $key
* @param string $key
* @return mixed
*/
protected function native_session_get(string $key)
@ -226,10 +227,10 @@ class Authkit2
}
/**
* Set a value in the $_SESSION variable
* Set a value in the $_SESSION variable.
*
* @param string $key
* @param mixed $value
* @param string $key
* @param mixed $value
* @return void
*/
protected function native_session_set(string $key, $value): void
@ -239,7 +240,7 @@ class Authkit2
}
/**
* Check whether a PHP session exists, and if not try and start one
* Check whether a PHP session exists, and if not try and start one.
*
* @internal
* @return void
@ -247,17 +248,21 @@ class Authkit2
protected function native_session_check(): void
{
if (session_status() == \PHP_SESSION_NONE)
{
session_start();
else if (session_status() == \PHP_SESSION_DISABLED)
throw new \Exception("Authkit2 requires PHP sessions are enabled");
}
elseif (session_status() == \PHP_SESSION_DISABLED)
{
throw new \Exception('Authkit2 requires PHP sessions are enabled');
}
}
/**
* Dummy cache implementation to avoid errors; always returns default
* Dummy cache implementation to avoid errors; always returns default.
*
* @todo Check if apcu is available and use if so? Fall back to temp files?
* @param string $key cache key to retrieve
* @param mixed $default value to return if the specified key is not found
* @param string $key cache key to retrieve
* @param mixed $default value to return if the specified key is not found
* @return mixed
*/
protected function native_cache_get(string $key, $default = null)
@ -266,10 +271,10 @@ class Authkit2
}
/**
* Dummy cache implementation
* Dummy cache implementation.
*
* @param string $key cache key to set
* @param mixed $value value to cache
* @param string $key cache key to set
* @param mixed $value value to cache
* @return void
*/
protected function native_cache_set(string $key, $value): void
@ -277,11 +282,11 @@ class Authkit2
}
/**
* Configure the authkit2 library
* Configure the authkit2 library.
*
* @param string $client_id
* @param string $client_secret
* @param string $endpoint
* @param string $client_id
* @param string $client_secret
* @param string $endpoint
* @return void
*/
protected function ak2_configure(string $client_id, string $client_secret, string $endpoint): void
@ -290,7 +295,7 @@ class Authkit2
}
/**
* Fetch a OIDC client authenticated as this application
* Fetch a OIDC client authenticated as this application.
*
* @return Oidc\Client
*/
@ -308,8 +313,8 @@ class Authkit2
* expired then requests will simply fail. This use case is intended for
* authenticating requests using tokens other applications have sent to us.
*
* @param string $access_token
* @param ?string $refresh_token
* @param string $access_token
* @param ?string $refresh_token
* @return Oidc\Token
*/
protected function ak2_get_token(string $access_token, ?string $refresh_token = null): Oidc\Token
@ -321,12 +326,11 @@ class Authkit2
* Refresh a token object -- generate a new access token from its
* refresh_token.
*
* @param Oidc\Token $token
* @param Oidc\Token $token
* @return Oidc\Token a newly generated token
*/
protected function ak2_refresh_token(Oidc\Token $token): Oidc\Token
{
return $this->client->refreshToken($token);
}
}

6
src/Events/UserEvent.php

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
/**
* Event providing a user model as context
* Event providing a user model as context.
*/
abstract class UserEvent
{
@ -16,14 +16,14 @@ abstract class UserEvent
use SerializesModels;
/**
* User that this event refers to
* User that this event refers to.
*
* @var mixed
*/
public $user;
/**
* Initialize new event
* Initialize new event.
*
* @param mixed $user
*/

8
src/Events/UserInfoEvent.php

@ -5,21 +5,21 @@ declare(strict_types=1);
namespace authkit2\Events;
/**
* Notification for a user along with their info provided by OIDC provider
* Notification for a user along with their info provided by OIDC provider.
*/
class UserInfoEvent extends UserEvent
{
/**
* Additional fields returned during login
* Additional fields returned during login.
*
* @var mixed
*/
public $fields;
/**
* Initialize new event
* Initialize new event.
*
* @param mixed $user
* @param mixed $user
* @param array<string,string> $fields
*/
public function __construct($user, array $fields)

8
src/Events/UserLogin.php

@ -5,21 +5,21 @@ declare(strict_types=1);
namespace authkit2\Events;
/**
* Notification that a user has logged into the app
* Notification that a user has logged into the app.
*/
class UserLogin extends UserEvent
{
/**
* Additional fields returned during login
* Additional fields returned during login.
*
* @var mixed
*/
public $user_info;
/**
* Initialize new event
* Initialize new event.
*
* @param mixed $user
* @param mixed $user
* @param array<string,string> $user_info
*/
public function __construct($user, array $user_info)

2
src/Events/UserLogout.php

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace authkit2\Events;
/**
* Notification that a user has logged out of the app
* Notification that a user has logged out of the app.
*/
class UserLogout extends UserEvent
{

17
src/Http/Controllers/AuthenticationController.php

@ -3,16 +3,17 @@
declare(strict_types=1);
namespace authkit2\Http\Controllers;
use Illuminate\Http\Request;
use authkit2\Models\Token;
/**
* Methods for handling user authentication operations
* Methods for handling user authentication operations.
*/
class AuthenticationController extends Controller
{
/**
* OIDC flow to mediate the actual login process and exchanges
* OIDC flow to mediate the actual login process and exchanges.
* @var \authkit2\Oidc\Flows\UserFlow
*/
protected $user_flow;
@ -23,7 +24,7 @@ class AuthenticationController extends Controller
}
/**
* Start the login flow for a user
* Start the login flow for a user.
*
* Redirects the user to the SSO service
*
@ -37,13 +38,13 @@ class AuthenticationController extends Controller
}
/**
* Handle the response from the SSO service
* Handle the response from the SSO service.
*
* Exchange the code for a token and fetches basic user information.
* Attempts to log the user into this app, and creates them if they
* don't exist. Then redirects the user to the configured post_login url.
*
* @param Request $request
* @param Request $request
* @return mixed
*/
public function callback(Request $request)
@ -96,12 +97,12 @@ class AuthenticationController extends Controller
abort(500);
die();
}
else if (!method_exists($user, 'save'))
elseif (!method_exists($user, 'save'))
{
abort(500);
die();
}
else if (!method_exists($user, 'getAuthIdentifierName'))
elseif (!method_exists($user, 'getAuthIdentifierName'))
{
abort(500);
die();
@ -149,7 +150,7 @@ class AuthenticationController extends Controller
}
/**
* Explicitly log out of this application and the SSO service
* Explicitly log out of this application and the SSO service.
*
* @return mixed
*/

2
src/Http/Controllers/Controller.php

@ -7,7 +7,7 @@ namespace authkit2\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
/**
* Base controller class
* Base controller class.
*/
class Controller extends BaseController
{

9
src/Models/Token.php

@ -1,11 +1,13 @@
<?php
declare(strict_types=1);
namespace authkit2\Models;
use \Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Model;
/**
* User's OIDC token
* User's OIDC token.
*
* @property string $id
* @property int $user_id
@ -23,10 +25,9 @@ class Token extends Model
protected $table = 'authkit2_token';
/**
* Disable Eloquent's default created/updated fields
* Disable Eloquent's default created/updated fields.
*
* @var bool
*/
public $timestamps = false;
}

22
src/Observers/UserObserver.php

@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
namespace authkit2\Observers;
use authkit2\Authkit2;
use authkit2\Models\Token;
@ -22,9 +25,9 @@ class UserObserver
/**
* Run in response to a user model being loaded, locating their token and
* creating a client to place on the model
* creating a client to place on the model.
*
* @param mixed $user
* @param mixed $user
* @return void
*/
public function retrieved($user): void
@ -40,11 +43,11 @@ class UserObserver
$user->authkit->setRefreshCallback(
/**
* When a token has been refreshed, save the updated values
* to the token model
* @param \authkit2\Oidc\Token $oidc_token
* to the token model.
* @param \authkit2\Oidc\Token $oidc_token
* @return void
*/
function(\authkit2\Oidc\Token $oidc_token) use ($token) : void {
static function(\authkit2\Oidc\Token $oidc_token) use ($token): void {
$token->access_token = $oidc_token->getAccessToken();
$token->refresh_token = $oidc_token->getRefreshToken();
$token->save();
@ -55,20 +58,22 @@ class UserObserver
* Before we save a user model, remove the token/client so the ORM doesn't
* try and write those out.
*
* @param mixed $user
* @param mixed $user
* @return void
*/
public function saving($user): void
{
if (isset($user->authkit))
{
static::$token_cache[$user->{$user->getAuthIdentifierName()}] = $user->authkit;
}
unset($user->authkit);
}
/**
* After a user model is saved, restore the client and token
* After a user model is saved, restore the client and token.
*
* @param mixed $user
* @param mixed $user
* @return void
*/
public function saved($user): void
@ -79,6 +84,5 @@ class UserObserver
$user->authkit = static::$token_cache[$user_id];
unset(static::$token_cache[$user_id]);
}
}
}

22
src/Oidc/Authentication/Authentication.php

@ -1,19 +1,21 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc\Authentication;
/**
* Abstract provider for signing/authenticating http requests
* Abstract provider for signing/authenticating http requests.
*/
abstract class Authentication
{
/**
* Authenticate the passed in HTTP request
* Authenticate the passed in HTTP request.
*
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @return \Psr\Http\Message\RequestInterface authenticated request
*/
public abstract function authenticate(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\RequestInterface;
abstract public function authenticate(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\RequestInterface;
/**
* Wrap this provider up as a middleware appropriate for use directly with
@ -24,13 +26,13 @@ abstract class Authentication
public function getMiddleware(): callable
{
$auth = $this;
return function(callable $handler) use ($auth) : callable {
return static function(callable $handler) use ($auth): callable {
/**
* @param \Psr\Http\Message\RequestInterface $request
* @param mixed[] $options
* @param \Psr\Http\Message\RequestInterface $request
* @param mixed[] $options
* @return mixed
*/
return function(\Psr\Http\Message\RequestInterface $request, array $options) use ($handler, $auth) {
return static function(\Psr\Http\Message\RequestInterface $request, array $options) use ($handler, $auth) {
return $handler(
$auth->authenticate($request),
$options
@ -40,9 +42,9 @@ abstract class Authentication
}
/**
* Fetch a guzzle client with the authentication middleware included
* Fetch a guzzle client with the authentication middleware included.
*
* @param mixed[] $options options to pass through to the guzzle client
* @param mixed[] $options options to pass through to the guzzle client
* @return \GuzzleHttp\Client
*/
public function getClient(array $options = []): \GuzzleHttp\Client

16
src/Oidc/Authentication/ClientAuthentication.php

@ -1,28 +1,30 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc\Authentication;
/**
* Authenticate requests as a oauth client
* Authenticate requests as a oauth client.
*/
class ClientAuthentication extends Authentication
{
/**
* Oauth client id
* Oauth client id.
* @var string
*/
protected $client_id;
/**
* Oauth client secret
* Oauth client secret.
* @var string
*/
protected $client_secret;
/**
* Create a new client authentication provider
* Create a new client authentication provider.
*
* @param string $client_id oauth client id
* @param string $client_id oauth client id
* @param string $client_secret oauth client secret
*/
public function __construct(string $client_id, string $client_secret)
@ -32,12 +34,12 @@ class ClientAuthentication extends Authentication
}
/**
* Authenticate the passed in request with the provided client credentials
* Authenticate the passed in request with the provided client credentials.
*
* Client authentication uses HTTP basic authentication with the client id
* as the username and the client secret as the password.
*
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @return \Psr\Http\Message\RequestInterface authenticated request
*/
public function authenticate(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\RequestInterface

27
src/Oidc/Authentication/TokenAuthentication.php

@ -1,30 +1,33 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc\Authentication;
use \authkit2\Oidc\Token;
use authkit2\Oidc\Token;
/**
* Authenticates requests using an oauth token from a service account
* or user
* or user.
*/
class TokenAuthentication extends Authentication
{
/**
* Token used to authenticate requests
* @var Token
*/
* Token used to authenticate requests.
* @var Token
*/
protected $token;
/**
* Who to call if the token is expired
* Who to call if the token is expired.
* @var ?callable
*/
protected $refresh_callback;
/**
* Create a new token authentication provider
* Create a new token authentication provider.
*
* @param Token $token token to authenticate requests with
* @param Token $token token to authenticate requests with
* @param ?callable $refreshCallback callback to generate us a new token when our existing one expires
*/
public function __construct(Token $token, callable $refreshCallback = null)
@ -34,9 +37,9 @@ class TokenAuthentication extends Authentication
}
/**
* Set the callback to be called when the underlying token expires
* Set the callback to be called when the underlying token expires.
*
* @param callable $refreshCallback
* @param callable $refreshCallback
* @return void
*/
public function setRefreshCallback(callable $refreshCallback): void
@ -45,11 +48,11 @@ class TokenAuthentication extends Authentication
}
/**
* Authenticate the passed in request with the provided token
* Authenticate the passed in request with the provided token.
*
* Token authentication uses the token as a bearer token.
*
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @param \Psr\Http\Message\RequestInterface $request request to authenticate
* @return \Psr\Http\Message\RequestInterface authenticated request
*/
public function authenticate(\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\RequestInterface

113
src/Oidc/Client.php

@ -1,52 +1,55 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc;
use authkit2\Authkit2;
/**
* OpenId Connect HTTP Client Library
* OpenId Connect HTTP Client Library.
*/
class Client
{
/**
* Authenticator used to authenticate requests we're making
* Authenticator used to authenticate requests we're making.
* @var Authentication\Authentication
*/
protected $auth;
/**
* Http client we've initialized with our authentication middleware in
* place
* place.
* @var \GuzzleHttp\Client
*/
protected $client;
/**
* OAuth client id
* OAuth client id.
* @var string
*/
protected $client_id;
/**
* Base url of the OIDC realm
* Base url of the OIDC realm.
* @var string
*/
protected $oidc_url;
/**
* OIDC config fetched from the server or restored from cache
* OIDC config fetched from the server or restored from cache.
* @var ?array<string,mixed>
*/
protected $oidc_config;
/**
* Keys for validating signed JWT tokens
* Keys for validating signed JWT tokens.
* @var array<string,mixed>
*/
protected $oidc_jwks;
/**
* Create a new OIDC client using the passed in client credentials
* Create a new OIDC client using the passed in client credentials.
*
* @param string $url
* @param string $client_id
@ -62,7 +65,7 @@ class Client
}
/**
* Retrieve a HTTP client containing our authentication middleware
* Retrieve a HTTP client containing our authentication middleware.
*
* @return \GuzzleHttp\Client
*/
@ -72,7 +75,7 @@ class Client
}
/**
* Retrieve the configured OpenId Connect realm url; null if never set
* Retrieve the configured OpenId Connect realm url; null if never set.
*
* @return ?string
*/
@ -82,7 +85,7 @@ class Client
}
/**
* Get the OpenId Connect configuration
* Get the OpenId Connect configuration.
*
* @return array<string,string|array|bool>
*/
@ -95,18 +98,17 @@ class Client
/**
* @return array<string,string|array|bool>
*/
function() use ($url) {
static function() use ($url) {
$response = (new \GuzzleHttp\Client())->get($url.'/.well-known/openid-configuration');
return json_decode($response->getBody(), true);
return json_decode((string)$response->getBody(), true);
}
);
}
return $this->oidc_config;
}
/**
* Get the web key set for verifying JWTs
* Get the web key set for verifying JWTs.
*
* @return array<string,array>
*/
@ -119,7 +121,7 @@ class Client
/**
* @return array<string,array>
*/
function() use ($client) {
static function() use ($client) {
$response = $client->get($client->getConfiguration()['jwks_uri']);
return json_decode(json_encode($response), true);
}
@ -129,7 +131,7 @@ class Client
}
/**
* Get the signing algorithms for signing JWTs
* Get the signing algorithms for signing JWTs.
*
* @return string[]
*/
@ -139,9 +141,9 @@ class Client
}
/**
* Fetch a specific OpenId Connect endpoint from the configuration
* Fetch a specific OpenId Connect endpoint from the configuration.
*
* @param string $endpoint_name
* @param string $endpoint_name
* @return string
*/
public function getEndpointUrl(string $endpoint_name): string
@ -150,40 +152,40 @@ class Client
}
/**
* Make a HTTP get request to a OIDC endpoint or other URL
* Make a HTTP get request to a OIDC endpoint or other URL.
*
* @param string $url
* @param array<string,scalar> $params query string parameters
* @return object json decoded response
* @param string $url
* @param array<string,scalar> $params query string parameters
* @return object json decoded response
*/
protected function get(string $url, array $params = []): object
{
$response = $this->getClient()->get($url, [
'query' => $params
]);
return json_decode($response->getBody());
return json_decode((string)$response->getBody());
}
/**
* Make a HTTP post request to a OIDC endpoint or other URL
*
* If form parameters are provided the request is sent as
* application/x-www-form-urlencoded
*
* @param string $url
* @param array<string,scalar> $params form fields
* @return object json decoded response
*/
* Make a HTTP post request to a OIDC endpoint or other URL.
*
* If form parameters are provided the request is sent as
* application/x-www-form-urlencoded
*
* @param string $url
* @param array<string,scalar> $params form fields
* @return object json decoded response
*/
protected function post(string $url, array $params = []): object
{
$response = $this->getClient()->post($url, [
'form_params' => $params
]);
return json_decode($response->getBody());
return json_decode((string)$response->getBody());
}
/**
* Create a 'service account' token tied to this client's id
* Create a 'service account' token tied to this client's id.
*
* @return Token
*/
@ -197,10 +199,10 @@ class Client
/**
* Convert a returned authorization code from the three legged flow
* into a token
* into a token.
*
* @param string $code
* @param string $redirect_uri
* @param string $code
* @param string $redirect_uri
* @return Token
*/
public function createTokenFromAuthorizationCode(string $code, string $redirect_uri): Token
@ -215,9 +217,9 @@ class Client
}
/**
* Create a new access token from a refresh token
* Create a new access token from a refresh token.
*
* @param string $refresh_token
* @param string $refresh_token
* @return Token
*/
public function createTokenFromRefreshToken(string $refresh_token): Token
@ -231,12 +233,12 @@ class Client
/**
* Generate the URL to redirect to in order to initiate the three-legged
* oauth flow
* oauth flow.
*
* @param string $redirect_uri url to redirect the user to after authentication
* @param string[] $scopes scopes to request from the openid provider
* @param string $state nonce
* @return string fully formed url
* @param string $redirect_uri url to redirect the user to after authentication
* @param string[] $scopes scopes to request from the openid provider
* @param string $state nonce
* @return string fully formed url
*/
public function createAuthorizationRedirectUrl(string $redirect_uri, array $scopes, string $state): string
{
@ -251,9 +253,9 @@ class Client
/**
* Generate the URL to redirect to in order to initiate a signout from the
* OIDC provider
* OIDC provider.
*
* @param string $redirect_uri url to redirect the user to after logout
* @param string $redirect_uri url to redirect the user to after logout
* @return string fully formed url
*/
public function createLogoutUrl(string $redirect_uri): string
@ -264,30 +266,31 @@ class Client
}
/**
* Refresh a token using a refresh token
* Refresh a token using a refresh token.
*
* @param Token $token expired token that includes a refresh token
* @param Token $token expired token that includes a refresh token
* @return Token newly generated token
*/
public function refreshToken(Token $token): Token
{
$refresh_token = $token->getRefreshToken();
if (!isset($refresh_token))
throw new \Exception("Cannot refresh token initialized without refresh token");
{
throw new \Exception('Cannot refresh token initialized without refresh token');
}
return $this->createTokenFromRefreshToken($refresh_token);
}
/**
* Fetch the available information on the user from the OIDC provider
* Fetch the available information on the user from the OIDC provider.
*
* @param Token $token token representing the user
* @param Token $token token representing the user
* @return array<string,mixed>
*/
public function getTokenUserInfo(Token $token): array
{
return json_decode($token->getClient()->get($this->getEndpointUrl('userinfo'))->getBody(), true);
return json_decode((string)$token->getClient()->get($this->getEndpointUrl('userinfo'))->getBody(), true);
}
// todo: introspect, etc
}

13
src/Oidc/Flows/ServiceAccountFlow.php

@ -1,22 +1,25 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc\Flows;
use authkit2\Oidc\Client;
use authkit2\Oidc\Token;
/**
* OpenId client_credentials grant flow
* OpenId client_credentials grant flow.
*/
class ServiceAccountFlow
{
/**
* oidc client for making requests authenticated with our id/secret
* oidc client for making requests authenticated with our id/secret.
* @var Client
*/
protected $client;
/**
* Initialize a new service account flow
* Initialize a new service account flow.
*
* @param Client $client
*/
@ -26,7 +29,7 @@ class ServiceAccountFlow
}
/**
* Fetch a service account token for the initialized credentials
* Fetch a service account token for the initialized credentials.
*
* @return Token
*/
@ -35,5 +38,3 @@ class ServiceAccountFlow
return $this->client->createTokenFromClient();
}
}

34
src/Oidc/Flows/UserFlow.php

@ -1,23 +1,26 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc\Flows;
use authkit2\Authkit2;
use authkit2\Oidc\Client;
use authkit2\Oidc\Token;
/**
* Oauth three legged auth flow for authenticating users
* Oauth three legged auth flow for authenticating users.
*/
class UserFlow
{
/**
* OIDC client
* OIDC client.
* @var Client
*/
protected $client;
/**
* Initialize a new user login flow
* Initialize a new user login flow.
*
* @param Client $client
*/
@ -27,11 +30,11 @@ class UserFlow
}
/**
* Get the URL the user should be redirected to to begin the authorization process
* Get the URL the user should be redirected to to begin the authorization process.
*
* @param string $redirect_uri url the oidc endpoint should redirect the user back to; generally must be authorized in the provider
* @param string[] $scopes the scopes to request in the token
* @return string url to redirect the user to
* @param string $redirect_uri url the oidc endpoint should redirect the user back to; generally must be authorized in the provider
* @param string[] $scopes the scopes to request in the token
* @return string url to redirect the user to
*/
public function getRedirectUrl(string $redirect_uri, array $scopes = ['email']): string
{
@ -47,15 +50,16 @@ class UserFlow
}
/**
* Validate that the provided state string is one we have previously generated
* Validate that the provided state string is one we have previously generated.
*
* @param string $state
* @throws \Exception if the state is unrecognized or invalid
* @return void
*/
public function validateState(string $state): void
{
$states = Authkit2::session_get('userflow.state') ?? [];
for ($i=0; $i<sizeof($states); $i++)
for ($i = 0; $i < sizeof($states); $i++)
{
if ($states[$i] == $state)
{
@ -64,17 +68,17 @@ class UserFlow
return;
}
}
throw new \Exception("Invalid auth nonce");
throw new \Exception('Invalid auth nonce');
}
/**
* After the user is redirected back with a authorization code, exchange it
* for an access token
* for an access token.
*
* THIS DOES NOT VALIDATE THE STATE. Call validateState first.
*
* @param string $code code returned by the authorization flow
* @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
* @param string $redirect_uri url the oidc endpoint redirects back to; must match one given in call to getRedirectUrl
* @return Token
*/
public function exchangeCodeForToken(string $code, string $redirect_uri): Token
@ -86,13 +90,11 @@ class UserFlow
* If we want to log out of the SSO service and all apps, the URL to hit to
* sign out everywhere.
*
* @param string $redirect_uri url to redirect back to after logout completes
* @param string $redirect_uri url to redirect back to after logout completes
* @return string
*/
public function getLogoutUrl(string $redirect_uri): string
{
return $this->client->createLogoutUrl($redirect_uri);
}
}

77
src/Oidc/Token.php

@ -1,59 +1,61 @@
<?php
declare(strict_types=1);
namespace authkit2\Oidc;
use authkit2\Oidc\Client;
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
/**
* A OpenId Connect token, optionally with a refresh token
* A OpenId Connect token, optionally with a refresh token.
*/
class Token
{
/**
* OIDC client
* OIDC client.
* @var Client
*/
protected $client = null;
/**
* OIDC JWT access token
* OIDC JWT access token.
* @var string
*/
protected $access_token;
/**
* OIDC JWT refresh token
* OIDC JWT refresh token.
* @var ?string
*/
protected $refresh_token;
/**
* Cache of userinfo endpoint response
* Cache of userinfo endpoint response.
* @var array<string,scalar>
*/
protected $user_info = null;
/**
* Decoded access token JWT data
* Decoded access token JWT data.
* @var array<string,mixed>
*/
protected $access_token_data = null;
/**
* Decoded refresh token JWT data
* Decoded refresh token JWT data.
* @var array<string,mixed>
*/
protected $refresh_token_data = null;
/**
* Callback to be notified when this token is refreshed
* Callback to be notified when this token is refreshed.
* @var callable
*/
protected $refresh_callback;
/**
* Initialize token with the from*() static methods
* Initialize token with the from*() static methods.
*/
protected function __construct()
{
@ -61,11 +63,11 @@ class Token
/**
* Create a token given a access_token and optionally refresh_token, passed
* as a string
* as a string.
*
* @param Client $client
* @param string $access_token
* @param ?string $refresh_token
* @param Client $client
* @param string $access_token
* @param ?string $refresh_token
* @return Token
*/
public static function fromString(Client $client, string $access_token, ?string $refresh_token = null): Token
@ -78,9 +80,9 @@ class Token
}
/**
* Get a HTTP client that's authenticated with this token's credentials
* Get a HTTP client that's authenticated with this token's credentials.
*
* @param array<string,mixed> $options
* @param array<string,mixed> $options
* @return \GuzzleHttp\Client
*/
public function getClient(array $options = []): \GuzzleHttp\Client
@ -90,13 +92,15 @@ class Token
$state = new \stdClass();
$state->refresher =
function(Token $token) use ($state) : Token {
function(Token $token) use ($state): Token {
$client = $this->client;
$refresh_callback = $this->refresh_callback;
// Refresh the token
if (!isset($this->refresh_token))
throw new \Exception("Token expired");
{
throw new \Exception('Token expired');
}
$new_token = $client->createTokenFromRefreshToken($this->refresh_token);
// Rebind this callback to the new token
@ -118,9 +122,9 @@ class Token
}
/**
* Callback to notify when this token is refreshed
* Callback to notify when this token is refreshed.
*
* @param callable $callback
* @param callable $callback
* @return void
*/
public function setRefreshCallback(callable $callback): void
@ -129,10 +133,10 @@ class Token
}
/**
* Create a token from a OIDC response from the token endpoint
* Create a token from a OIDC response from the token endpoint.
*
* @param Client $client
* @param object $response
* @param Client $client
* @param object $response
* @return Token
*/
public static function fromResponse(Client $client, object $response): Token
@ -145,7 +149,7 @@ class Token
}
/**
* Fetch the raw decoded data out of our JWT access token
* Fetch the raw decoded data out of our JWT access token.
*
* @return array<string,mixed>
*/
@ -159,7 +163,7 @@ class Token
}
/**
* Fetch the raw decoded data out of our JWT refresh token
* Fetch the raw decoded data out of our JWT refresh token.
*
* @return array<string,mixed>
*/
@ -169,7 +173,7 @@ class Token
{
if (!isset($this->refresh_token))
{
throw new \UnexpectedValueException("Refresh token not set!");
throw new \UnexpectedValueException('Refresh token not set!');
}
$this->refresh_token_data = json_decode(json_encode($this->decode($this->refresh_token)), true);
}
@ -177,9 +181,9 @@ class Token
}
/**
* Decode a token as a JWT token
* Decode a token as a JWT token.
*
* @param string $token
* @param string $token
* @return object
*/
protected function decode(string $token): object
@ -223,7 +227,7 @@ class Token
}
/**
* Check whether the access token is expired
* Check whether the access token is expired.
*
* As long as the refresh token is valid, this is recoverly by calling
* passing this token to refresh on the client.
@ -236,7 +240,9 @@ class Token
{
$token_data = $this->getAccessTokenData();
if ($token_data['exp'] <= time())
{
return true;
}
return false;
}
catch (\Firebase\JWT\ExpiredException $ex)
@ -246,7 +252,7 @@ class Token
}
/**
* Check whether this token needs a refresh to be used
* Check whether this token needs a refresh to be used.
*
* @return bool
*/
@ -256,7 +262,7 @@ class Token
}
/**
* Fetch the underlying access token this token represents
* Fetch the underlying access token this token represents.
*
* @return string
*/
@ -266,7 +272,7 @@ class Token
}
/**
* Fetch the user's refresh token
* Fetch the user's refresh token.
*
* @return ?string
*/
@ -277,7 +283,7 @@ class Token
/**
* Fetch the user info associated with this token from the OIDC
* provider
* provider.
*
* @return array<string,scalar>
*/
@ -287,7 +293,7 @@ class Token
}
/**
* Fetch the roles encoded in this token
* Fetch the roles encoded in this token.
*
* @return string[]
*/
@ -297,7 +303,7 @@ class Token
}
/**
* Fetch the uuid encoded in this token
* Fetch the uuid encoded in this token.
*
* @return string
*/
@ -305,5 +311,4 @@ class Token
{
return 'crn:user:'.$this->getAccessTokenData()['sub'];
}
}

8
src/Providers/Authkit2ServiceProvider.php

@ -1,15 +1,16 @@
<?php
declare(strict_types=1);
namespace authkit2\Providers;
use Illuminate\Support\ServiceProvider;
/**
* Core Authkit2 provider
* Core Authkit2 provider.
*/
class Authkit2ServiceProvider extends ServiceProvider
{
/**
* Register all providers and other components for any enabled features
* of the library.
@ -32,7 +33,7 @@ class Authkit2ServiceProvider extends ServiceProvider
}
/**
* Register publishable resources
* Register publishable resources.
*
* @return void
*/
@ -55,4 +56,3 @@ class Authkit2ServiceProvider extends ServiceProvider
}
}
}

16
src/Providers/AuthnServiceProvider.php

@ -5,30 +5,30 @@ declare(strict_types=1);
namespace authkit2\Providers;
use Illuminate\Support\ServiceProvider;
use \authkit2\Authkit2;
use authkit2\Authkit2;
/**
* Authentication provider to perform setup for authentication processes
* Authentication provider to perform setup for authentication processes.
*/
class AuthnServiceProvider extends ServiceProvider
{
/**
* Register the additional service providers the authentication process depends on
* Register the additional service providers the authentication process depends on.
*
* @return void
*/
public function register(): void
{
$this->app->singleton(\authkit2\Oidc\Flows\ServiceAccountFlow::class, function() : \authkit2\Oidc\Flows\ServiceAccountFlow {
$this->app->singleton(\authkit2\Oidc\Flows\ServiceAccountFlow::class, static function(): \authkit2\Oidc\Flows\ServiceAccountFlow {
return new \authkit2\Oidc\Flows\ServiceAccountFlow(Authkit2::get_client());
});
$this->app->singleton(\authkit2\Oidc\Flows\UserFlow::class, function() : \authkit2\Oidc\Flows\UserFlow {
$this->app->singleton(\authkit2\Oidc\Flows\UserFlow::class, static function(): \authkit2\Oidc\Flows\UserFlow {
return new \authkit2\Oidc\Flows\UserFlow(Authkit2::get_client());
});
}
/**
* Initialize and register all authentication resources
* Initialize and register all authentication resources.
*
* @return void
*/
@ -83,7 +83,7 @@ class AuthnServiceProvider extends ServiceProvider
/**
* Generate any missing config values for keycloak by reading JSON
* auth config
* auth config.
*
* @return void
*/
@ -125,7 +125,7 @@ class AuthnServiceProvider extends ServiceProvider
// running a composer require/composer install without credentials present.
if (config('authkit.authn.openid.client_id') != null && config('authkit.authn.openid.client_secret') != null && config('authkit.authn.openid.endpoint') != null)
{
$this->app->booted(function() {
$this->app->booted(static function() {
Authkit2::configure(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'), config('authkit.authn.openid.endpoint'));
});
}

6
src/Providers/AuthzServiceProvider.php

@ -8,12 +8,12 @@ use Illuminate\Support\ServiceProvider;
/**
* Authorization provider to register and configure all
* assets involved in permission checking
* assets involved in permission checking.
*/
class AuthzServiceProvider extends ServiceProvider
{
/**
* Register the additional service providers the authorization process depends on
* Register the additional service providers the authorization process depends on.
*
* @return void
*/
@ -22,7 +22,7 @@ class AuthzServiceProvider extends ServiceProvider
}
/**
* Initialize and register all authorization resources
* Initialize and register all authorization resources.
*
* @return void
*/

Loading…
Cancel
Save