Skip to content

Commit

Permalink
Use cacheable OpenID Configuration (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
ricklambrechts authored Mar 29, 2023
1 parent d529ec8 commit 7fdff54
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 7 deletions.
16 changes: 13 additions & 3 deletions config/oidc.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@
'code_challenge_method' => env('OIDC_CODE_CHALLENGE_METHOD', 'S256'),

/**
* TTL of the OpenID configuration cache in seconds.
*/
'configuration_cache_ttl' => env('OIDC_CONFIGURATION_CACHE_TTL', 60 * 60 * 24),
* Configuration Cache
*/
'configuration_cache' => [
/**
* The cache store to use.
*/
'store' => env('OIDC_CONFIGURATION_CACHE_DRIVER', 'file'),

/**
* The cache TTL in seconds.
*/
'ttl' => env('OIDC_CONFIGURATION_CACHE_TTL', 60 * 60 * 24),
],

/**
* Route configuration
Expand Down
32 changes: 31 additions & 1 deletion src/OpenIDConnectClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,29 @@
namespace MinVWS\OpenIDConnectLaravel;

use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use Jumbojett\OpenIDConnectClient as BaseOpenIDConnectClient;
use Jumbojett\OpenIDConnectClientException;
use MinVWS\OpenIDConnectLaravel\OpenIDConfiguration\OpenIDConfiguration;
use MinVWS\OpenIDConnectLaravel\Services\JWE\JweDecryptInterface;

class OpenIDConnectClient extends BaseOpenIDConnectClient
{
protected ?JweDecryptInterface $jweDecrypter;
protected ?OpenIDConfiguration $openIDConfiguration;

public function __construct(
?string $providerUrl = null,
?string $clientId = null,
?string $clientSecret = null,
?string $issuer = null,
?JweDecryptInterface $jweDecrypter = null
?JweDecryptInterface $jweDecrypter = null,
?OpenIDConfiguration $openIDConfiguration = null,
) {
parent::__construct($providerUrl, $clientId, $clientSecret, $issuer);

$this->jweDecrypter = $jweDecrypter;
$this->openIDConfiguration = $openIDConfiguration;
}

protected function startSession(): void
Expand Down Expand Up @@ -78,4 +83,29 @@ protected function handleJweResponse($jwe): string
}
return $this->jweDecrypter->decrypt($jwe);
}

/**
* Use cached OpenID configuration if available.
*
* @param string $param
* @param string $default optional
* @throws OpenIDConnectClientException
* @return string|string[]|bool
* @psalm-suppress ImplementedReturnTypeMismatch
*/
protected function getWellKnownConfigValue($param, $default = null): string|array|bool
{
if ($this->openIDConfiguration === null) {
return parent::getWellKnownConfigValue($param, $default);
}

$config = $this->openIDConfiguration;
$param = Str::camel($param);

if (!property_exists($config, $param)) {
return parent::getWellKnownConfigValue($param, $default);
}

return $config->{$param};
}
}
7 changes: 4 additions & 3 deletions src/OpenIDConnectServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ protected function registerConfigurationLoader(): void
$this->app->singleton(OpenIDConfigurationLoader::class, function (Application $app) {
return new OpenIDConfigurationLoader(
$app['config']->get('oidc.issuer'),
$app['config']->get('oidc.cache_ttl'),
$app['config']->get('oidc.cache_store'),
$app['cache']->store($app['config']->get('oidc.configuration_cache.store')),
$app['config']->get('oidc.configuration_cache.ttl'),
);
});
}
Expand All @@ -75,7 +75,8 @@ protected function registerClient(): void
$this->app->singleton(OpenIDConnectClient::class, function (Application $app) {
$oidc = new OpenIDConnectClient(
providerUrl: $app['config']->get('oidc.issuer'),
jweDecrypter: $app->make(JweDecryptInterface::class)
jweDecrypter: $app->make(JweDecryptInterface::class),
openIDConfiguration: $app->make(OpenIDConfigurationLoader::class)->getConfiguration(),
);
$oidc->setClientID($app['config']->get('oidc.client_id'));
if (!empty($app['config']->get('oidc.client_secret'))) {
Expand Down
23 changes: 23 additions & 0 deletions tests/Feature/OpenIDConfigurationLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,29 @@ public function testLoaderReturnsEmptyConfigurationOnEmptyJsonResponse(): void
$this->assertEmpty($configuration->tokenEndpoint);
}

public function testConfigurationIsLoadedMultipleTimesWhenCacheStoreIsNull(): void
{
$this->fakeSuccessfulResponse();

$loader = new OpenIDConfigurationLoader(
issuer: 'https://provider.rdobeheer.nl',
cacheStore: Cache::store('null'),
);

// Load 2 times
$loader->getConfiguration();
$configuration = $loader->getConfiguration();

Http::assertSentCount(2);

$this->assertSame("3.0", $configuration->version);
$this->assertSame("https://provider.rdobeheer.nl", $configuration->issuer);
$this->assertSame("https://provider.rdobeheer.nl/authorize", $configuration->authorizationEndpoint);
$this->assertSame("https://provider.rdobeheer.nl/jwks", $configuration->jwksUri);
$this->assertSame("https://provider.rdobeheer.nl/token", $configuration->tokenEndpoint);
$this->assertSame("https://provider.rdobeheer.nl/userinfo", $configuration->userinfoEndpoint);
}

protected function fakeSuccessfulResponse(): void
{
Http::fake([
Expand Down

0 comments on commit 7fdff54

Please sign in to comment.