diff options
author | John LeSueur <jlesueur@bamboohr.com> | 2014-06-23 15:06:27 +0000 |
---|---|---|
committer | John LeSueur <jlesueur@bamboohr.com> | 2014-06-23 15:06:27 +0000 |
commit | b5829858aed4a1f73c3029ecaf3e34471a083e6e (patch) | |
tree | 363afd247dfd959b3c32e02cd4dfbddb47b666b3 | |
parent | 144e201a30f96119eafe1c597b0736612b86317c (diff) | |
download | php-jwt-b5829858aed4a1f73c3029ecaf3e34471a083e6e.zip php-jwt-b5829858aed4a1f73c3029ecaf3e34471a083e6e.tar.gz php-jwt-b5829858aed4a1f73c3029ecaf3e34471a083e6e.tar.bz2 |
1. Allow encode to take a "kid" parameter
2. Allow decode to take an array of keys, and use the "kid" to look up the key.
3. Add RS256 as an algorithm
4. Add tests for the above
-rw-r--r-- | Authentication/JWT.php | 47 | ||||
-rw-r--r-- | tests/JWTTest.php | 19 |
2 files changed, 41 insertions, 25 deletions
diff --git a/Authentication/JWT.php b/Authentication/JWT.php index 875a177..aa4995d 100644 --- a/Authentication/JWT.php +++ b/Authentication/JWT.php @@ -32,32 +32,12 @@ class JWT 'HS384' => array('hash_hmac', 'SHA384'), 'RS256' => array('openssl', 'SHA256'), ); - /** - * Returns just the header portion of the jwt. This allows - * you to determine which key should be used to verify - * the jwt, using the "kid" field - * - * @param string $jwt - * - * @return object The JWT's header object, with fields "typ","alg", and optionally "kid" - */ - public static function decodeHeader($jwt) { - $tks = explode('.', $jwt); - if (count($tks) != 3) { - throw new UnexpectedValueException('Wrong number of segments'); - } - list($headb64, $bodyb64, $cryptob64) = $tks; - if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) { - throw new UnexpectedValueException('Invalid segment encoding'); - } - return $header; - } /** * Decodes a JWT string into a PHP object. * * @param string $jwt The JWT - * @param string|null $key The secret key + * @param string|Array|null $key The secret key, or map of keys * @param bool $verify Don't skip verification process * * @return object The JWT's payload as a PHP object @@ -85,6 +65,11 @@ class JWT if (empty($header->alg)) { throw new DomainException('Empty algorithm'); } + if (is_array($key) && !isset($header->kid)) { + throw new DomainException('"kid" empty, unable to lookup correct key'); + } elseif(is_array($key) && isset($header->kid)) { + $key = $key[$header->kid]; + } if (!JWT::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) { throw new UnexpectedValueException('Signature verification failed'); } @@ -108,10 +93,12 @@ class JWT * @uses jsonEncode * @uses urlsafeB64Encode */ - public static function encode($payload, $key, $algo = 'HS256') + public static function encode($payload, $key, $algo = 'HS256', $keyId = null) { $header = array('typ' => 'JWT', 'alg' => $algo); - + if($keyId !== null) { + $header['kid'] = $keyId; + } $segments = array(); $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header)); $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload)); @@ -127,7 +114,7 @@ class JWT * Sign a string with a given key and algorithm. * * @param string $msg The message to sign - * @param string $key The secret key + * @param string|resource $key The secret key * @param string $method The signing algorithm. Supported * algorithms are 'HS256', 'HS384' and 'HS512' * @@ -154,6 +141,16 @@ class JWT } } + /** + * Verify a signature with the mesage, key and method. Not all methods + * are symmetric, so we must have a separate verify and sign method. + * @param string $msg the original message + * @param string $signature + * @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key + * @param string $method + * @return bool + * @throws DomainException Invalid Algorithm or OpenSSL failure + */ public static function verify($msg, $signature, $key, $method = 'HS256') { if (empty(self::$methods[$method])) { throw new DomainException('Algorithm not supported'); @@ -163,7 +160,7 @@ class JWT case 'openssl': $success = openssl_verify($msg, $signature, $key, $algo); if(!$success) { - throw new DomainException("OpenSSL unable to sign data"); + throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string()); } else { return $signature; } diff --git a/tests/JWTTest.php b/tests/JWTTest.php index ae65f02..5aa5dc7 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -46,6 +46,25 @@ class JWTTest extends PHPUnit_Framework_TestCase { $decoded = JWT::decode($encoded, 'my_key'); $this->assertEquals($decoded->message, 'abc'); } + + function testRSEncodeDecode() { + $privKey = openssl_pkey_new(array('digest_alg' => 'sha256', + 'private_key_bits' => 1024, + 'private_key_type' => OPENSSL_KEYTYPE_RSA)); + $msg = JWT::encode('abc',$privKey, 'RS256'); + $pubKey = openssl_pkey_get_details($privKey); + $pubKey = $pubKey['key']; + $decoded = JWT::decode($msg, $pubKey, true); + $this->assertEquals($decoded, 'abc'); + } + + function testKIDChooser() { + $keys = array('1' => 'my_key', '2' => 'my_key2'); + $msg = JWT::encode('abc', $keys['1'], 'HS256', '1'); + $decoded = JWT::decode($msg, $keys, true); + $this->assertEquals($decoded, 'abc'); + } + } |