Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand Configuration Properties (and Refactor Config Builder) #381

Merged
merged 6 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 149 additions & 35 deletions src/Auth0.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
use Auth0\SDK\Auth0 as SDK;
use Auth0\SDK\Configuration\SdkConfiguration as Configuration;
use Auth0\SDK\Contract\API\ManagementInterface;
use Auth0\SDK\Contract\Auth0Interface as SDKContract;
use Auth0\SDK\Contract\{Auth0Interface as SDKContract, StoreInterface};
use Auth0\SDK\Utility\HttpTelemetry;
use Psr\Cache\CacheItemPoolInterface;

use function in_array;
use function is_string;

/**
* Service that provides access to the Auth0 SDK.
Expand All @@ -31,9 +33,144 @@ final class Auth0 implements ServiceContract
public function __construct(
private ?SDKContract $sdk = null,
private ?Configuration $configuration = null,
private ?CacheItemPoolInterface $tokenCachePool = null,
private ?CacheItemPoolInterface $managementTokenCachePool = null,
) {
}

private function bootManagementTokenCache(array $config): array
{
$managementTokenCache = $config['managementTokenCache'] ?? null;

if (false === $managementTokenCache) {
unset($config['managementTokenCache']);

return $config;
}

if (null === $managementTokenCache) {
$managementTokenCache = $this->getManagementTokenCachePool();
}

if (is_string($managementTokenCache)) {
$managementTokenCache = app(trim($managementTokenCache));
}

$config['managementTokenCache'] = $managementTokenCache instanceof CacheItemPoolInterface ? $managementTokenCache : null;

return $config;
}

private function bootSessionStorage(array $config): array
{
$sessionStorage = $config['sessionStorage'] ?? null;
$sessionStorageId = $config['sessionStorageId'] ?? 'auth0_session';

if (false === $sessionStorage) {
unset($config['sessionStorage']);

return $config;
}

if (null === $sessionStorage) {
$sessionStorage = app(LaravelSession::class, [
'prefix' => $sessionStorageId,
]);
}

if (is_string($sessionStorage)) {
$sessionStorage = app(trim($sessionStorage), [
'prefix' => $sessionStorageId,
]);
}

$config['sessionStorage'] = $sessionStorage instanceof StoreInterface ? $sessionStorage : null;

return $config;
}

private function bootStrategy(array $config): array
{
$strategy = $config['strategy'] ?? Configuration::STRATEGY_REGULAR;

if (! is_string($strategy)) {
$strategy = Configuration::STRATEGY_REGULAR;
}

$config['strategy'] = $strategy;

return $config;
}

private function bootTokenCache(array $config): array
{
$tokenCache = $config['tokenCache'] ?? null;

if (false === $tokenCache) {
unset($config['tokenCache']);

return $config;
}

if (null === $tokenCache) {
$tokenCache = $this->getTokenCachePool();
}

if (is_string($tokenCache)) {
$tokenCache = app(trim($tokenCache));
}

$config['tokenCache'] = $tokenCache instanceof CacheItemPoolInterface ? $tokenCache : null;

return $config;
}

private function bootTransientStorage(array $config): array
{
$transientStorage = $config['transientStorage'] ?? null;
$transientStorageId = $config['transientStorageId'] ?? 'auth0_transient';

if (false === $transientStorage) {
unset($config['transientStorage']);

return $config;
}

if (null === $transientStorage) {
$transientStorage = app(LaravelSession::class, [
'prefix' => $transientStorageId,
]);
}

if (is_string($transientStorage)) {
$transientStorage = app(trim($transientStorage), [
'prefix' => $transientStorageId,
]);
}

$config['transientStorage'] = $transientStorage instanceof StoreInterface ? $transientStorage : null;

return $config;
}

private function getManagementTokenCachePool(): CacheItemPoolInterface
{
if (! $this->managementTokenCachePool instanceof CacheItemPoolInterface) {
$this->managementTokenCachePool = app(LaravelCachePool::class);
}

return $this->managementTokenCachePool;
}

private function getTokenCachePool(): CacheItemPoolInterface
{
if (! $this->tokenCachePool instanceof CacheItemPoolInterface) {
$this->tokenCachePool = app(LaravelCachePool::class);
}

return $this->tokenCachePool;
}

/**
* Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers.
*/
Expand All @@ -53,49 +190,26 @@ public function getConfiguration(): Configuration
/**
* @var array<mixed> $config
*/
if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) {
$cache = new LaravelCachePool();

if (! isset($config['tokenCache'])) {
$config['tokenCache'] = $cache;
}

if (! isset($config['managementTokenCache'])) {
$config['managementTokenCache'] = $cache;
}
}

// Give host application an opportunity to update the configuration before assigning defaults.
$event = new Building($config);
event($event);
$config = $event->getConfiguration();

$configuration = new Configuration($event->getConfiguration());
$config = $this->bootStrategy($config);
$config = $this->bootTokenCache($config);
$config = $this->bootManagementTokenCache($config);

if (! in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) {
// If no sessionStorage is defined, use an LaravelSession store instance.
if (! isset($config['sessionStorage'])) {
$sessionStore = app(LaravelSession::class, [
'prefix' => $configuration->getSessionStorageId(),
]);

$configuration->setSessionStorage(sessionStorage: $sessionStore);
}

// If no transientStorage is defined, use an LaravelSession store instance.
if (! isset($config['transientStorage'])) {
$transientStore = app(LaravelSession::class, [
'prefix' => $configuration->getTransientStorageId(),
]);

$configuration->setTransientStorage(transientStorage: $transientStore);
}
if (in_array($config['strategy'], Configuration::STRATEGIES_USING_SESSIONS, true)) {
$config = $this->bootSessionStorage($config);
$config = $this->bootTransientStorage($config);
}

$this->configuration = $configuration;
$config = new Configuration($config);

// Give apps an opportunity to mutate the configuration before applying it.
$event = new Built($configuration);
// Give host application an opportunity to update the configuration before applying it.
$event = new Built($config);
event($event);

$this->configuration = $event->getConfiguration();
}

Expand Down
104 changes: 104 additions & 0 deletions tests/Unit/Auth0Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,107 @@
$updated = spl_object_id($laravel->getSdk());
expect($cache)->not->toBe($updated);
});

test('bootStrategy() rejects non-string values', function (): void {
$method = new ReflectionMethod(Auth0::class, 'bootStrategy');
$method->setAccessible(true);

expect($method->invoke($this->laravel, ['strategy' => 123]))
->toMatchArray(['strategy' => SdkConfiguration::STRATEGY_REGULAR]);
});

test('bootSessionStorage() behaves as expected', function (): void {
$method = new ReflectionMethod(Auth0::class, 'bootSessionStorage');
$method->setAccessible(true);

expect($method->invoke($this->laravel, []))
->sessionStorage->toBeInstanceOf(LaravelSession::class);

expect($method->invoke($this->laravel, ['sessionStorage' => null]))
->sessionStorage->toBeInstanceOf(LaravelSession::class);

expect($method->invoke($this->laravel, ['sessionStorage' => false]))
->sessionStorage->toBeNull();

expect($method->invoke($this->laravel, ['sessionStorage' => LaravelCachePool::class]))
->sessionStorage->toBeNull();

expect($method->invoke($this->laravel, ['sessionStorage' => MemoryStore::class]))
->sessionStorage->toBeInstanceOf(MemoryStore::class);

$this->app->singleton('testStore', static fn (): MemoryStore => app(MemoryStore::class));

expect($method->invoke($this->laravel, ['sessionStorage' => 'testStore']))
->sessionStorage->toBeInstanceOf(MemoryStore::class);
});

test('bootTransientStorage() behaves as expected', function (): void {
$method = new ReflectionMethod(Auth0::class, 'bootTransientStorage');
$method->setAccessible(true);

expect($method->invoke($this->laravel, []))
->transientStorage->toBeInstanceOf(LaravelSession::class);

expect($method->invoke($this->laravel, ['transientStorage' => null]))
->transientStorage->toBeInstanceOf(LaravelSession::class);

expect($method->invoke($this->laravel, ['transientStorage' => false]))
->transientStorage->toBeNull();

expect($method->invoke($this->laravel, ['transientStorage' => LaravelCachePool::class]))
->transientStorage->toBeNull();

expect($method->invoke($this->laravel, ['transientStorage' => MemoryStore::class]))
->transientStorage->toBeInstanceOf(MemoryStore::class);

$this->app->singleton('testStore', static fn (): MemoryStore => app(MemoryStore::class));

expect($method->invoke($this->laravel, ['transientStorage' => 'testStore']))
->transientStorage->toBeInstanceOf(MemoryStore::class);
});

test('bootTokenCache() behaves as expected', function (): void {
$method = new ReflectionMethod(Auth0::class, 'bootTokenCache');
$method->setAccessible(true);

expect($method->invoke($this->laravel, []))
->tokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['tokenCache' => null]))
->tokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['tokenCache' => LaravelCachePool::class]))
->tokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['tokenCache' => false]))
->tokenCache->toBeNull();

expect($method->invoke($this->laravel, ['tokenCache' => MemoryStore::class]))
->tokenCache->toBeNull();

expect($method->invoke($this->laravel, ['tokenCache' => 'cache.psr6']))
->tokenCache->toBeInstanceOf(CacheItemPoolInterface::class);
});

test('bootManagementTokenCache() behaves as expected', function (): void {
$method = new ReflectionMethod(Auth0::class, 'bootManagementTokenCache');
$method->setAccessible(true);

expect($method->invoke($this->laravel, []))
->managementTokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['managementTokenCache' => null]))
->managementTokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['managementTokenCache' => LaravelCachePool::class]))
->managementTokenCache->toBeInstanceOf(LaravelCachePool::class);

expect($method->invoke($this->laravel, ['managementTokenCache' => false]))
->managementTokenCache->toBeNull();

expect($method->invoke($this->laravel, ['managementTokenCache' => MemoryStore::class]))
->managementTokenCache->toBeNull();

expect($method->invoke($this->laravel, ['managementTokenCache' => 'cache.psr6']))
->managementTokenCache->toBeInstanceOf(CacheItemPoolInterface::class);
});