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

Add code for each Exception #456

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 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
2 changes: 1 addition & 1 deletion src/BeforeValidException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Firebase\JWT;

class BeforeValidException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
class BeforeValidException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface, JwtExceptionInterface
{
private object $payload;

Expand Down
26 changes: 19 additions & 7 deletions src/CachedKeySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ public function __construct(
public function offsetGet($keyId): Key
{
if (!$this->keyIdExists($keyId)) {
throw new OutOfBoundsException('Key ID not found');
throw new OutOfBoundsException(
'Key ID not found',
JwtExceptionInterface::KEY_ID_NOT_FOUND
);
}
return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
}
Expand All @@ -121,15 +124,21 @@ public function offsetExists($keyId): bool
*/
public function offsetSet($offset, $value): void
{
throw new LogicException('Method not implemented');
throw new LogicException(
'Method not implemented',
JwtExceptionInterface::OFFSET_SET_METHOD_NOT_IMPLEMENTED
);
}

/**
* @param string $offset
*/
public function offsetUnset($offset): void
{
throw new LogicException('Method not implemented');
throw new LogicException(
'Method not implemented',
JwtExceptionInterface::OFFSET_UNSET_METHOD_NOT_IMPLEMENTED
);
}

/**
Expand All @@ -140,11 +149,11 @@ private function formatJwksForCache(string $jwks): array
$jwks = json_decode($jwks, true);

if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
throw new UnexpectedValueException('"keys" member must exist in the JWK Set', JwtExceptionInterface::CACHED_KEY_MISSING);
}

if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
throw new InvalidArgumentException('JWK Set did not contain any keys', JwtExceptionInterface::CACHED_KEY_EMPTY);
}

$keys = [];
Expand Down Expand Up @@ -185,7 +194,7 @@ private function keyIdExists(string $keyId): bool
$jwksResponse->getReasonPhrase(),
$this->jwksUri,
),
$jwksResponse->getStatusCode()
JwtExceptionInterface::CACHED_KEY_GET_JWK
);
}
$this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
Expand Down Expand Up @@ -243,7 +252,10 @@ private function getCacheItem(): CacheItemInterface
private function setCacheKeys(): void
{
if (empty($this->jwksUri)) {
throw new RuntimeException('JWKS URI is empty');
throw new RuntimeException(
'JWKS URI is empty',
JwtExceptionInterface::JWKS_URI_IS_EMPTY
);
}

// ensure we do not have illegal characters
Expand Down
2 changes: 1 addition & 1 deletion src/ExpiredException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Firebase\JWT;

class ExpiredException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
class ExpiredException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface, JwtExceptionInterface
{
private object $payload;

Expand Down
72 changes: 55 additions & 17 deletions src/JWK.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,17 @@ public static function parseKeySet(array $jwks, ?string $defaultAlg = null): arr
$keys = [];

if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
throw new UnexpectedValueException(
'"keys" member must exist in the JWK Set',
JwtExceptionInterface::JWK_MISSING_KEYS
);
}

if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
throw new InvalidArgumentException(
'JWK Set did not contain any keys',
JwtExceptionInterface::JWT_KEYS_IS_EMPTY
);
}

foreach ($jwks['keys'] as $k => $v) {
Expand All @@ -72,7 +78,11 @@ public static function parseKeySet(array $jwks, ?string $defaultAlg = null): arr
}

if (0 === \count($keys)) {
throw new UnexpectedValueException('No supported algorithms found in JWK Set');
throw new UnexpectedValueException(
'No supported algorithms found in JWK Set',
JwtExceptionInterface::JWT_ALGORITHM_NOT_SUPPORTED

);
}

return $keys;
Expand All @@ -96,11 +106,17 @@ public static function parseKeySet(array $jwks, ?string $defaultAlg = null): arr
public static function parseKey(array $jwk, ?string $defaultAlg = null): ?Key
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
throw new InvalidArgumentException(
'JWK must not be empty',
JwtExceptionInterface::JWK_IS_EMPTY
);
}

if (!isset($jwk['kty'])) {
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
throw new UnexpectedValueException(
'JWK must contain a "kty" parameter',
JwtExceptionInterface::JWT_MISSING_KTY_PARAMETER
);
}

if (!isset($jwk['alg'])) {
Expand All @@ -109,64 +125,86 @@ public static function parseKey(array $jwk, ?string $defaultAlg = null): ?Key
// for parsing in this library. Use the $defaultAlg parameter when parsing the
// key set in order to prevent this error.
// @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
throw new UnexpectedValueException('JWK must contain an "alg" parameter');
throw new UnexpectedValueException(
'JWK must contain an "alg" parameter',
JwtExceptionInterface::JWT_MISSING_ALG_PARAMETER
);
}
$jwk['alg'] = $defaultAlg;
}

switch ($jwk['kty']) {
case 'RSA':
if (!empty($jwk['d'])) {
throw new UnexpectedValueException('RSA private keys are not supported');
throw new UnexpectedValueException(
'RSA private keys are not supported',
JwtExceptionInterface::JWT_RSA_KEYS_NOT_SUPPORTED
);
}
if (!isset($jwk['n']) || !isset($jwk['e'])) {
throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
throw new UnexpectedValueException(
'RSA keys must contain values for both "n" and "e"',
JwtExceptionInterface::JWT_RSA_KEYS_MISSING_N_AND_E
);
}

$pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
$publicKey = \openssl_pkey_get_public($pem);
if (false === $publicKey) {
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
'OpenSSL error: ' . \openssl_error_string(),
JwtExceptionInterface::JWT_OPEN_SSL_ERROR
);
}
return new Key($publicKey, $jwk['alg']);
case 'EC':
if (isset($jwk['d'])) {
// The key is actually a private key
throw new UnexpectedValueException('Key data must be for a public key');
throw new UnexpectedValueException(
'Key data must be for a public key',
JwtExceptionInterface::JWK_EC_D_IS_NOT_SET
);
}

if (empty($jwk['crv'])) {
throw new UnexpectedValueException('crv not set');
throw new UnexpectedValueException(
'crv not set',
JwtExceptionInterface::JWT_EC_CRV_IS_EMPTY
);
}

if (!isset(self::EC_CURVES[$jwk['crv']])) {
throw new DomainException('Unrecognised or unsupported EC curve');
throw new DomainException(
'Unrecognised or unsupported EC curve',
JwtExceptionInterface::JWK_UNSUPPORTED_EC_CURVE
);
}

if (empty($jwk['x']) || empty($jwk['y'])) {
throw new UnexpectedValueException('x and y not set');
throw new UnexpectedValueException(
'x and y not set',
JwtExceptionInterface::JWT_X_AND_Y_ARE_EMPTY
);
}

$publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
return new Key($publicKey, $jwk['alg']);
case 'OKP':
if (isset($jwk['d'])) {
// The key is actually a private key
throw new UnexpectedValueException('Key data must be for a public key');
throw new UnexpectedValueException('Key data must be for a public key', JwtExceptionInterface::JWK_OKP_MISSING);
}

if (!isset($jwk['crv'])) {
throw new UnexpectedValueException('crv not set');
throw new UnexpectedValueException('crv not set', JwtExceptionInterface::JWT_CRV_MISSING);
}

if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
throw new DomainException('Unrecognised or unsupported OKP key subtype');
throw new DomainException('Unrecognised or unsupported OKP key subtype', JwtExceptionInterface::JWT_CRV_UNSUPPORTED);
}

if (empty($jwk['x'])) {
throw new UnexpectedValueException('x not set');
throw new UnexpectedValueException('x not set', JwtExceptionInterface::JWT_X_MISSING);
}

// This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
Expand Down
Loading