|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace authkit2\Providers;
|
|
|
|
|
|
|
|
use Illuminate\Support\ServiceProvider;
|
|
|
|
use authkit2\Authkit2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Authentication provider to perform setup for authentication processes.
|
|
|
|
*/
|
|
|
|
class AuthnServiceProvider extends ServiceProvider
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Register the additional service providers the authentication process depends on.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function register(): void
|
|
|
|
{
|
|
|
|
$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, static function(): \authkit2\Oidc\Flows\UserFlow {
|
|
|
|
return new \authkit2\Oidc\Flows\UserFlow(Authkit2::get_client());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize and register all authentication resources.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function boot(): void
|
|
|
|
{
|
|
|
|
// register our observer on the user model so we can dynamically add/remove
|
|
|
|
// the token object + client
|
|
|
|
$user_model = (string)config('auth.providers.users.model');
|
|
|
|
$user_model::observe(\authkit2\Observers\UserObserver::class);
|
|
|
|
|
|
|
|
// Register all authentication routes
|
|
|
|
$this->bootRoutes();
|
|
|
|
// Load keycloak configuration and set in Laravel config()
|
|
|
|
$this->bootConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register all authentication routes
|
|
|
|
* If not already cached, generate and register the URL the SSO service
|
|
|
|
* should redirect back to.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
protected function bootRoutes(): void
|
|
|
|
{
|
|
|
|
// Load routes
|
|
|
|
\Route::group(config('authkit.authn.routing'), function() {
|
|
|
|
$this->loadRoutesFrom(__DIR__.'/../../routes/web.php');
|
|
|
|
});
|
|
|
|
|
|
|
|
// Figure out where the route is after booting
|
|
|
|
if (!config()->has('authkit.authn.openid.redirect_uri'))
|
|
|
|
{
|
|
|
|
$this->app->booted(static function() {
|
|
|
|
// TODO: For some reason route($name) isn't working here. We're
|
|
|
|
// just looking through the routes manually for now...
|
|
|
|
|
|
|
|
// Might shoot ourselves in the foot if the routing system is
|
|
|
|
// ever changed, but for now this works and this whole method
|
|
|
|
// is a hack anyway.
|
|
|
|
// @phan-suppress-next-line PhanTypeNoPropertiesForeach
|
|
|
|
foreach (\Route::getRoutes() as $route)
|
|
|
|
{
|
|
|
|
if ($route->getName() === 'login.callback')
|
|
|
|
{
|
|
|
|
config(['authkit.authn.openid.redirect_uri' => url($route->uri())]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new \Exception('Route [login.callback] not found');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate any missing config values for keycloak by reading JSON
|
|
|
|
* auth config.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
protected function bootConfig(): void
|
|
|
|
{
|
|
|
|
// We check if the values are available because they may have
|
|
|
|
// previously been generated and cached by Laravel in which case
|
|
|
|
// we can save some work.
|
|
|
|
if (!(config()->has('authkit.authn.openid.client_id') &&
|
|
|
|
config()->has('authkit.authn.openid.client_secret') &&
|
|
|
|
config()->has('authkit.authn.openid.endpoint')))
|
|
|
|
{
|
|
|
|
// Figure out where to load the config from
|
|
|
|
$disk = config('authkit.authn.config.disk');
|
|
|
|
$path = config('authkit.authn.config.path');
|
|
|
|
if (!\Storage::disk($disk)->exists($path))
|
|
|
|
{
|
|
|
|
// If it doesn't exist, skip the loading.
|
|
|
|
$config_json = [];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$config_raw = \Storage::disk($disk)->get($path);
|
|
|
|
$config_json = json_decode($config_raw, true);
|
|
|
|
if (!isset($config_json))
|
|
|
|
{
|
|
|
|
throw new \Exception("Could not parse authentication configuration at $disk:$path");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
config([
|
|
|
|
'authkit.authn.openid.client_id' => env('AUTHKIT_CLIENT_ID', $config_json['resource'] ?? null),
|
|
|
|
'authkit.authn.openid.client_secret' => env('AUTHKIT_CLIENT_SECRET', $config_json['credentials']['secret'] ?? null),
|
|
|
|
'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)
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't even try and init authkit unless configuration is present, prevents erroring out when
|
|
|
|
// 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(static function() {
|
|
|
|
Authkit2::configure(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'), config('authkit.authn.openid.endpoint'));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|