mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-05 17:16:52 +03:00
Fixed OIDC handling when no JWKS 'use' prop exists
Now assume, based on OIDC discovery spec, that keys without 'use' are 'sig' keys. Should not affect existing use-cases since existance of such keys would have throw exceptions in prev. versions of bookstack. For #3869
This commit is contained in:
parent
85b7b10c01
commit
e20c944350
@ -67,11 +67,10 @@ class OidcJwtSigningKey
|
|||||||
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}");
|
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($jwk['use'])) {
|
// 'use' is optional for a JWK but we assume 'sig' where no value exists since that's what
|
||||||
throw new OidcInvalidKeyException('A "use" parameter on the provided key is expected');
|
// the OIDC discovery spec infers since 'sig' MUST be set if encryption keys come into play.
|
||||||
}
|
$use = $jwk['use'] ?? 'sig';
|
||||||
|
if ($use !== 'sig') {
|
||||||
if ($jwk['use'] !== 'sig') {
|
|
||||||
throw new OidcInvalidKeyException("Only signature keys are currently supported. Found key for use {$jwk['use']}");
|
throw new OidcInvalidKeyException("Only signature keys are currently supported. Found key for use {$jwk['use']}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,40 +15,17 @@ use Psr\Http\Client\ClientInterface;
|
|||||||
*/
|
*/
|
||||||
class OidcProviderSettings
|
class OidcProviderSettings
|
||||||
{
|
{
|
||||||
/**
|
public string $issuer;
|
||||||
* @var string
|
public string $clientId;
|
||||||
*/
|
public string $clientSecret;
|
||||||
public $issuer;
|
public ?string $redirectUri;
|
||||||
|
public ?string $authorizationEndpoint;
|
||||||
/**
|
public ?string $tokenEndpoint;
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $clientId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $clientSecret;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $redirectUri;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $authorizationEndpoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $tokenEndpoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]|array[]
|
* @var string[]|array[]
|
||||||
*/
|
*/
|
||||||
public $keys = [];
|
public ?array $keys = [];
|
||||||
|
|
||||||
public function __construct(array $settings)
|
public function __construct(array $settings)
|
||||||
{
|
{
|
||||||
@ -164,9 +141,10 @@ class OidcProviderSettings
|
|||||||
protected function filterKeys(array $keys): array
|
protected function filterKeys(array $keys): array
|
||||||
{
|
{
|
||||||
return array_filter($keys, function (array $key) {
|
return array_filter($keys, function (array $key) {
|
||||||
$alg = $key['alg'] ?? null;
|
$alg = $key['alg'] ?? 'RS256';
|
||||||
|
$use = $key['use'] ?? 'sig';
|
||||||
|
|
||||||
return $key['kty'] === 'RSA' && $key['use'] === 'sig' && (is_null($alg) || $alg === 'RS256');
|
return $key['kty'] === 'RSA' && $use === 'sig' && $alg === 'RS256';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@ class OidcService
|
|||||||
{
|
{
|
||||||
$settings = $this->getProviderSettings();
|
$settings = $this->getProviderSettings();
|
||||||
$provider = $this->getProvider($settings);
|
$provider = $this->getProvider($settings);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'url' => $provider->getAuthorizationUrl(),
|
'url' => $provider->getAuthorizationUrl(),
|
||||||
'state' => $provider->getState(),
|
'state' => $provider->getState(),
|
||||||
|
@ -360,6 +360,37 @@ class OidcTest extends TestCase
|
|||||||
$this->assertTrue(auth()->check());
|
$this->assertTrue(auth()->check());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_auth_login_with_autodiscovery_with_keys_that_do_not_have_use_property()
|
||||||
|
{
|
||||||
|
// Based on reading the OIDC discovery spec:
|
||||||
|
// > This contains the signing key(s) the RP uses to validate signatures from the OP. The JWK Set MAY also
|
||||||
|
// > contain the Server's encryption key(s), which are used by RPs to encrypt requests to the Server. When
|
||||||
|
// > both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all
|
||||||
|
// > keys in the referenced JWK Set to indicate each key's intended usage.
|
||||||
|
// We can assume that keys without use are intended for signing.
|
||||||
|
$this->withAutodiscovery();
|
||||||
|
|
||||||
|
$keyArray = OidcJwtHelper::publicJwkKeyArray();
|
||||||
|
unset($keyArray['use']);
|
||||||
|
|
||||||
|
$this->mockHttpClient([
|
||||||
|
$this->getAutoDiscoveryResponse(),
|
||||||
|
new Response(200, [
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Cache-Control' => 'no-cache, no-store',
|
||||||
|
'Pragma' => 'no-cache',
|
||||||
|
], json_encode([
|
||||||
|
'keys' => [
|
||||||
|
$keyArray,
|
||||||
|
],
|
||||||
|
])),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertFalse(auth()->check());
|
||||||
|
$this->runLogin();
|
||||||
|
$this->assertTrue(auth()->check());
|
||||||
|
}
|
||||||
|
|
||||||
public function test_login_group_sync()
|
public function test_login_group_sync()
|
||||||
{
|
{
|
||||||
config()->set([
|
config()->set([
|
||||||
|
Loading…
x
Reference in New Issue
Block a user