Skip to content

Commit

Permalink
Feedback: better custom JWKS URI handling
Browse files Browse the repository at this point in the history
  • Loading branch information
joshcanhelp committed Feb 10, 2020
1 parent 23bcdb6 commit 378d823
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/API/Helpers/RequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class RequestBuilder
public function __construct(array $config)
{
$this->method = $config['method'];
$this->domain = $config['domain'];
$this->domain = $config['domain'] ?? '';
$this->basePath = $config['basePath'] ?? '';
$this->guzzleOptions = $config['guzzleOptions'] ?? [];
$this->headers = $config['headers'] ?? [];
Expand Down
2 changes: 1 addition & 1 deletion src/Auth0.php
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ public function decodeIdToken(string $idToken, array $verifierOptions = []) : ar
$idTokenIss = 'https://'.$this->domain.'/';
$sigVerifier = null;
if ('RS256' === $this->idTokenAlg) {
$jwksHttpOptions = array_merge( [ 'jwks_uri' => $this->jwksUri ], $this->guzzleOptions );
$jwksHttpOptions = array_merge( $this->guzzleOptions, [ 'base_uri' => $this->jwksUri ] );
$jwksFetcher = new JWKFetcher($this->cacheHandler, $jwksHttpOptions);
$sigVerifier = new AsymmetricVerifier($jwksFetcher);
} else if ('HS256' === $this->idTokenAlg) {
Expand Down
29 changes: 11 additions & 18 deletions src/Helpers/JWKFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,22 @@ class JWKFetcher
*
* @var array
*/
private $httpOptions;

/**
* JWKS URI to use, set in $httpOptions['jwks_uri'].
*
* @var array
*/
private $jwksUri;
private $guzzleOptions;

/**
* JWKFetcher constructor.
*
* @param CacheInterface|null $cache Cache handler or null for no caching.
* @param array $httOptions HTTP options, including Guzzle options.
* @param CacheInterface|null $cache Cache handler or null for no caching.
* @param array $guzzleOptions Guzzle HTTP options.
*/
public function __construct(CacheInterface $cache = null, array $httOptions = [])
public function __construct(CacheInterface $cache = null, array $guzzleOptions = [])
{
if ($cache === null) {
$cache = new NoCacheHandler();
}

$this->cache = $cache;
$this->httpOptions = $httOptions;
$this->jwksUri = $this->httpOptions['jwks_uri'] ?? null;
unset( $this->httpOptions['jwks_uri'] );
$this->cache = $cache;
$this->guzzleOptions = $guzzleOptions;
}

/**
Expand Down Expand Up @@ -106,7 +97,7 @@ public function getKey(string $kid, string $jwksUri = null)
*/
public function getKeys(string $jwks_url = null, bool $use_cache = true) : array
{
$jwks_url = $jwks_url ?? $this->jwksUri;
$jwks_url = $jwks_url ?? $this->guzzleOptions['base_uri'] ?? '';
if (empty( $jwks_url )) {
return [];
}
Expand Down Expand Up @@ -148,11 +139,13 @@ public function getKeys(string $jwks_url = null, bool $use_cache = true) : array
*/
protected function requestJwks(string $jwks_url) : array
{
$options = array_merge( $this->guzzleOptions, [ 'base_uri' => $jwks_url ] );

$request = new RequestBuilder([
'domain' => $jwks_url,
'method' => 'GET',
'guzzleOptions' => $this->httpOptions
'guzzleOptions' => $options,
]);

return $request->call();
}
}
19 changes: 7 additions & 12 deletions tests/Helpers/JWKFetcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,17 @@ public function testThatGetKeysUsesOptionsUrl()
$jwks_body = '{"keys":[{"kid":"__kid_1__","x5c":["__x5c_1__"]}]}';
$jwks = new MockJwks(
[ new Response( 200, [ 'Content-Type' => 'application/json' ], $jwks_body ) ],
[
'cache' => new ArrayCachePool(),
'jwks_uri' => '__test_custom_uri__',
]
[ 'cache' => new ArrayCachePool() ],
[ 'base_uri' => '__test_jwks_url__' ]
);

$jwks->call()->getKeys();
$this->assertEquals( '__test_custom_uri__', $jwks->getHistoryUrl() );
$this->assertEquals( '__test_jwks_url__', $jwks->getHistoryUrl() );
}

public function testThatGetKeyGetsSpecificKid() {
$cache = new ArrayCachePool();
$jwks = new JWKFetcher( $cache, [ 'jwks_uri' => '__test_jwks_url__' ] );
$jwks = new JWKFetcher( $cache, [ 'base_uri' => '__test_jwks_url__' ] );
$cache->set(md5('__test_jwks_url__'), ['__test_kid_1__' => '__test_x5c_1__']);
$this->assertEquals('__test_x5c_1__', $jwks->getKey('__test_kid_1__'));
}
Expand All @@ -131,19 +129,16 @@ public function testThatGetKeyBreaksCacheIsKidMissing() {
$jwks_body = '{"keys":[{"kid":"__test_kid_2__","x5c":["__test_x5c_2__"]}]}';
$jwks = new MockJwks(
[ new Response( 200, [ 'Content-Type' => 'application/json' ], $jwks_body ) ],
[
'cache' => $cache,
'jwks_uri' => '__test_jwks_url__',
]
[ 'cache' => $cache ],
[ 'base_uri' => '__test_jwks_url__' ]
);

$cache->set(md5('__test_jwks_url__'), ['__test_kid_1__' => '__test_x5c_1__']);

$this->assertContains('__test_x5c_2__', $jwks->call()->getKey('__test_kid_2__'));
}

public function testThatEmptyUrlReturnsEmptyKeys()
{
public function testThatEmptyUrlReturnsEmptyKeys() {
$jwks_formatted_1 = (new JWKFetcher())->getKeys();
$this->assertEquals( [], $jwks_formatted_1 );
}
Expand Down
3 changes: 0 additions & 3 deletions tests/Helpers/MockJwks.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ class MockJwks extends MockApi
public function setClient(array $guzzleOptions, array $config = [])
{
$cache = isset( $config['cache'] ) && $config['cache'] instanceof CacheInterface ? $config['cache'] : null;

$guzzleOptions['jwks_uri'] = isset( $config['jwks_uri'] ) ? $config['jwks_uri'] : null;

$this->client = new JWKFetcher( $cache, $guzzleOptions );
}
}
4 changes: 2 additions & 2 deletions tests/MockApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ abstract class MockApi
*
* @param array $responses Array of GuzzleHttp\Psr7\Response objects.
* @param array $config Additional optional configuration needed for mocked class.
* @param array $guzzleOptions Additional Guzzle HTTP options.
*/
public function __construct(array $responses = [], array $config = [])
public function __construct(array $responses = [], array $config = [], array $guzzleOptions = [])
{
$guzzleOptions = [];
if (count( $responses )) {
$mock = new MockHandler($responses);
$handler = HandlerStack::create($mock);
Expand Down

0 comments on commit 378d823

Please sign in to comment.