Skip to content

Add code for each Exception #456

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

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
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
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could clean this up quite a bit by making JWTExceptionWithPayloadInterface extend 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change!

);
}
$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 @@
$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 @@
}

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 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,75 +125,97 @@
// 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.
$publicKey = JWT::convertBase64urlToBase64($jwk['x']);

Check failure on line 211 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method convertBase64urlToBase64() on an unknown class Firebase\JWT\JWT.
return new Key($publicKey, $jwk['alg']);
case 'oct':
if (!isset($jwk['k'])) {
throw new UnexpectedValueException('k not set');
}

return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']);

Check failure on line 218 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method urlsafeB64Decode() on an unknown class Firebase\JWT\JWT.
default:
break;
}
Expand Down Expand Up @@ -213,8 +251,8 @@
self::encodeDER(
self::ASN1_BIT_STRING,
\chr(0x00) . \chr(0x04)
. JWT::urlsafeB64Decode($x)

Check failure on line 254 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method urlsafeB64Decode() on an unknown class Firebase\JWT\JWT.
. JWT::urlsafeB64Decode($y)

Check failure on line 255 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method urlsafeB64Decode() on an unknown class Firebase\JWT\JWT.
)
);

Expand All @@ -238,8 +276,8 @@
string $n,
string $e
): string {
$mod = JWT::urlsafeB64Decode($n);

Check failure on line 279 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method urlsafeB64Decode() on an unknown class Firebase\JWT\JWT.
$exp = JWT::urlsafeB64Decode($e);

Check failure on line 280 in src/JWK.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Call to static method urlsafeB64Decode() on an unknown class Firebase\JWT\JWT.

$modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
$publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
Expand Down
Loading
Loading