diff --git a/CHANGELOG.md b/CHANGELOG.md index ed661d2..cb50b49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Per-provider `cache_duration` option (seconds) forwarded to the + underlying library; lets consumers tighten or extend the 24h default + TTL for the cached OIDC discovery document and JWKS - Per-provider `http_client_options` block (`timeout`, `proxy`, `verify`) forwarded to the underlying Guzzle HTTP client used by league/oauth2-client. Closes the long-standing inability to bound HTTP requests to the IdP. diff --git a/README.md b/README.md index dcd63c5..4892b13 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ itkdev_openid_connect: # Optional: Specify leeway (seconds) to account for clock skew between provider and hosting # Defaults to 10 leeway: '%env(int:ADMIN_OIDC_LEEWAY)%' + # Optional: Cache duration (seconds) for the OIDC discovery document and JWKS + # Defaults to 86400 (24 hours) + cache_duration: '%env(int:ADMIN_OIDC_CACHE_DURATION)%' # Optional: Allow (non-secure) http requests (used for mocking a IdP). NOT RECOMMENDED FOR PRODUCTION. # Defaults to false allow_http: '%env(bool:ADMIN_OIDC_ALLOW_HTTP)%' @@ -133,6 +136,7 @@ ADMIN_OIDC_CLIENT_ID=ADMIN_APP_CLIENT_ID ADMIN_OIDC_CLIENT_SECRET=ADMIN_APP_CLIENT_SECRET ADMIN_OIDC_REDIRECT_URI=ADMIN_APP_REDIRECT_URI ADMIN_OIDC_LEEWAY=30 +ADMIN_OIDC_CACHE_DURATION=86400 ADMIN_OIDC_ALLOW_HTTP=false # "user" open id connect configuration variables diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 562fb2d..a6bd2a4 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -65,6 +65,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Leeway in seconds to account for clock skew between server and provider') ->defaultValue(10) ->end() + ->integerNode('cache_duration') + ->info('Cache duration in seconds for the OIDC discovery document and JWKS (default: 86400 — 24 hours)') + ->defaultValue(86400) + ->end() ->scalarNode('redirect_uri') ->info('Redirect URI registered at identity provider') ->cannotBeEmpty() diff --git a/src/Security/OpenIdConfigurationProviderManager.php b/src/Security/OpenIdConfigurationProviderManager.php index 942f4a6..b431210 100644 --- a/src/Security/OpenIdConfigurationProviderManager.php +++ b/src/Security/OpenIdConfigurationProviderManager.php @@ -24,6 +24,7 @@ class OpenIdConfigurationProviderManager * redirect_route?: string, * redirect_route_parameters?: array, * leeway?: int, + * cache_duration?: int, * allow_http?: bool, * http_client_options?: array{ * timeout?: float, @@ -79,6 +80,10 @@ public function getProvider(string $key): OpenIdConfigurationProvider $providerOptions['leeway'] = $options['leeway']; } + if (isset($options['cache_duration'])) { + $providerOptions['cacheDuration'] = $options['cache_duration']; + } + if (isset($options['allow_http'])) { $providerOptions['allowHttp'] = $options['allow_http']; } diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php index 878d847..b6ef9e0 100644 --- a/tests/DependencyInjection/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -56,6 +56,7 @@ public function testMinimalConfig(): void $this->assertSame('my_id', $provider['client_id']); $this->assertSame('my_secret', $provider['client_secret']); $this->assertSame(10, $provider['leeway']); + $this->assertSame(86400, $provider['cache_duration']); $this->assertFalse($provider['allow_http']); } @@ -64,6 +65,7 @@ public function testFullConfig(): void $input = $this->getMinimalConfig(); $input['user_provider'] = 'my_user_provider'; $input['openid_providers']['provider1']['options']['leeway'] = 30; + $input['openid_providers']['provider1']['options']['cache_duration'] = 3600; $input['openid_providers']['provider1']['options']['redirect_uri'] = 'https://app.com/callback'; $input['openid_providers']['provider1']['options']['allow_http'] = true; @@ -76,6 +78,7 @@ public function testFullConfig(): void $provider = $config['openid_providers']['provider1']['options']; $this->assertSame(30, $provider['leeway']); + $this->assertSame(3600, $provider['cache_duration']); $this->assertSame('https://app.com/callback', $provider['redirect_uri']); $this->assertTrue($provider['allow_http']); } diff --git a/tests/Security/OpenIdConfigurationProviderManagerTest.php b/tests/Security/OpenIdConfigurationProviderManagerTest.php index 7d722bd..10840cc 100644 --- a/tests/Security/OpenIdConfigurationProviderManagerTest.php +++ b/tests/Security/OpenIdConfigurationProviderManagerTest.php @@ -107,6 +107,19 @@ public function testGetProviderWithLeeway(): void $this->assertInstanceOf(OpenIdConfigurationProvider::class, $provider); } + public function testGetProviderWithCacheDuration(): void + { + $manager = $this->createManager([ + 'test' => $this->getBaseProviderConfig() + [ + 'redirect_uri' => 'https://app.com/callback', + 'cache_duration' => 3600, + ], + ]); + + $provider = $manager->getProvider('test'); + $this->assertInstanceOf(OpenIdConfigurationProvider::class, $provider); + } + public function testGetProviderWithAllowHttp(): void { $manager = $this->createManager([