X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/263384cf99864ebdb0408fd4e478f783aa487c1a..refs/pull/3918/head:/app/Auth/Access/Oidc/OidcJwtSigningKey.php diff --git a/app/Auth/Access/Oidc/OidcJwtSigningKey.php b/app/Auth/Access/Oidc/OidcJwtSigningKey.php index 3e77cf331..f003ec93c 100644 --- a/app/Auth/Access/Oidc/OidcJwtSigningKey.php +++ b/app/Auth/Access/Oidc/OidcJwtSigningKey.php @@ -18,15 +18,17 @@ class OidcJwtSigningKey * Can be created either from a JWK parameter array or local file path to load a certificate from. * Examples: * 'file:///var/www/cert.pem' - * ['kty' => 'RSA', 'alg' => 'RS256', 'n' => 'abc123...'] + * ['kty' => 'RSA', 'alg' => 'RS256', 'n' => 'abc123...']. + * * @param array|string $jwkOrKeyPath + * * @throws OidcInvalidKeyException */ public function __construct($jwkOrKeyPath) { if (is_array($jwkOrKeyPath)) { $this->loadFromJwkArray($jwkOrKeyPath); - } else if (is_string($jwkOrKeyPath) && strpos($jwkOrKeyPath, 'file://') === 0) { + } elseif (is_string($jwkOrKeyPath) && strpos($jwkOrKeyPath, 'file://') === 0) { $this->loadFromPath($jwkOrKeyPath); } else { throw new OidcInvalidKeyException('Unexpected type of key value provided'); @@ -39,16 +41,18 @@ class OidcJwtSigningKey protected function loadFromPath(string $path) { try { - $this->key = PublicKeyLoader::load( + $key = PublicKeyLoader::load( file_get_contents($path) - )->withPadding(RSA::SIGNATURE_PKCS1); + ); } catch (\Exception $exception) { throw new OidcInvalidKeyException("Failed to load key from file path with error: {$exception->getMessage()}"); } - if (!($this->key instanceof RSA)) { - throw new OidcInvalidKeyException("Key loaded from file path is not an RSA key as expected"); + if (!$key instanceof RSA) { + throw new OidcInvalidKeyException('Key loaded from file path is not an RSA key as expected'); } + + $this->key = $key->withPadding(RSA::SIGNATURE_PKCS1); } /** @@ -56,15 +60,17 @@ class OidcJwtSigningKey */ protected function loadFromJwkArray(array $jwk) { - if ($jwk['alg'] !== 'RS256') { - throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$jwk['alg']}"); - } - - if (empty($jwk['use'])) { - throw new OidcInvalidKeyException('A "use" parameter on the provided key is expected'); + // 'alg' is optional for a JWK, but we will still attempt to validate if + // it exists otherwise presume it will be compatible. + $alg = $jwk['alg'] ?? null; + if ($jwk['kty'] !== 'RSA' || !(is_null($alg) || $alg === 'RS256')) { + throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}"); } - if ($jwk['use'] !== 'sig') { + // 'use' is optional for a JWK but we assume 'sig' where no value exists since that's what + // the OIDC discovery spec infers since 'sig' MUST be set if encryption keys come into play. + $use = $jwk['use'] ?? 'sig'; + if ($use !== 'sig') { throw new OidcInvalidKeyException("Only signature keys are currently supported. Found key for use {$jwk['use']}"); } @@ -79,14 +85,19 @@ class OidcJwtSigningKey $n = strtr($jwk['n'] ?? '', '-_', '+/'); try { - /** @var RSA $key */ - $this->key = PublicKeyLoader::load([ + $key = PublicKeyLoader::load([ 'e' => new BigInteger(base64_decode($jwk['e']), 256), 'n' => new BigInteger(base64_decode($n), 256), - ])->withPadding(RSA::SIGNATURE_PKCS1); + ]); } catch (\Exception $exception) { throw new OidcInvalidKeyException("Failed to load key from JWK parameters with error: {$exception->getMessage()}"); } + + if (!$key instanceof RSA) { + throw new OidcInvalidKeyException('Key loaded from file path is not an RSA key as expected'); + } + + $this->key = $key->withPadding(RSA::SIGNATURE_PKCS1); } /** @@ -104,5 +115,4 @@ class OidcJwtSigningKey { return $this->key->toString('PKCS8'); } - -} \ No newline at end of file +}