diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d6a04058 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea +*.iml +bin +build +composer.lock +vendor diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..f4958dd8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: php + +php: + - 5.3.3 + - 5.4 + - 5.5 + +before_script: + - composer self-update + - composer install --dev --prefer-source --no-interaction + +script: ./bin/phpunit diff --git a/README.md b/README.md index 2f9e4392..3eb7e96e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ +JWT Implementation in PHP +========================= + +[![Travis](https://travis-ci.org/nixilla/php-jwt.png)](https://travis-ci.org/nixilla/php-jwt) + +```php + +``` + +Installation +============ + +```json +{ + "require": { + "nixilla/php-jwt": "dev-master" + } +} +``` PHP-JWT ======= @@ -8,20 +32,20 @@ Example ------- ```php "http://example.org/", "aud" => "http://example.com/", "iat" => 1356999524, "nbf" => 1357000000 - ); +); - $jwt = JWT::encode($token, $key); - $decoded = JWT::decode($jwt, $key); +$jwt = JWT::encode($token, $key); +$decoded = JWT::decode($jwt, $key); - print_r($decoded); +print_r($decoded); ?> ``` @@ -30,12 +54,12 @@ Tests Run the tests using phpunit: ```bash - $ pear install PHPUnit - $ phpunit tests/ - PHPUnit 3.7.10 by Sebastian Bergmann. - ..... - Time: 0 seconds, Memory: 2.50Mb - OK (5 tests, 5 assertions) +git clone https://github.com/jwmickey/php-jwt.git && \ +cd php-jwt && \ +mkdir bin && \ +curl -sS https://getcomposer.org/installer | php -- --install-dir=bin && \ +./bin/composer.phar install --dev && \ +./bin/phpunit ``` License diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..d2b72823 --- /dev/null +++ b/composer.json @@ -0,0 +1,41 @@ +{ + "name": "nixilla/php-jwt", + "description": "Json Web Token for PHP", + "type": "library", + "keywords": [ "jwt" ], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net" + }, + { + "name": "Jody Mickey", + "email": "jody.mickey@gmail.com" + }, + { + "name": "Janusz Slota", + "email": "janusz.slota@nixilla.com", + "homepage": "http://www.nixilla.com/", + "role": "Developer" + } + ], + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "autoload": { + "psr-0": { + "JWT": "lib/" + } + }, + "config": { + "bin-dir": "bin" + } +} \ No newline at end of file diff --git a/example.php b/example.php new file mode 100644 index 00000000..28527586 --- /dev/null +++ b/example.php @@ -0,0 +1,19 @@ + "http://example.org/", + "aud" => "http://example.com/", + "iat" => 1356999524, + "nbf" => 1357000000 +); + +$jwt = JWT::encode($token, $key); +$decoded = JWT::decode($jwt, $key); + +print_r($decoded); diff --git a/Authentication/JWT.php b/lib/JWT/Authentication/JWT.php similarity index 80% rename from Authentication/JWT.php rename to lib/JWT/Authentication/JWT.php index 7a7b4a0e..a5023b0d 100644 --- a/Authentication/JWT.php +++ b/lib/JWT/Authentication/JWT.php @@ -13,17 +13,9 @@ * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD * @link https://github.com/firebase/php-jwt */ -/** - * JSON Web Token implementation, based on this spec: - * http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06 - * - * @category Authentication - * @package Authentication_JWT - * @author Neuman Vong - * @author Anant Narayanan - * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD - * @link https://github.com/firebase/php-jwt - */ + +namespace JWT\Authentication; + class JWT { /** @@ -34,8 +26,8 @@ class JWT * @param bool $verify Don't skip verification process * * @return object The JWT's payload as a PHP object - * @throws UnexpectedValueException Provided JWT was invalid - * @throws DomainException Algorithm was not provided + * @throws \UnexpectedValueException Provided JWT was invalid + * @throws \DomainException Algorithm was not provided * * @uses jsonDecode * @uses urlsafeB64Decode @@ -44,22 +36,22 @@ public static function decode($jwt, $key = null, $verify = true) { $tks = explode('.', $jwt); if (count($tks) != 3) { - throw new UnexpectedValueException('Wrong number of segments'); + 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'); + throw new \UnexpectedValueException('Invalid segment encoding'); } if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) { - throw new UnexpectedValueException('Invalid segment encoding'); + throw new \UnexpectedValueException('Invalid segment encoding'); } $sig = JWT::urlsafeB64Decode($cryptob64); if ($verify) { if (empty($header->alg)) { - throw new DomainException('Empty algorithm'); + throw new \DomainException('Empty algorithm'); } if ($sig != JWT::sign("$headb64.$bodyb64", $key, $header->alg)) { - throw new UnexpectedValueException('Signature verification failed'); + throw new \UnexpectedValueException('Signature verification failed'); } } return $payload; @@ -101,7 +93,7 @@ public static function encode($payload, $key, $algo = 'HS256') * algorithms are 'HS256', 'HS384' and 'HS512' * * @return string An encrypted message - * @throws DomainException Unsupported algorithm was specified + * @throws \DomainException Unsupported algorithm was specified */ public static function sign($msg, $key, $method = 'HS256') { @@ -111,7 +103,7 @@ public static function sign($msg, $key, $method = 'HS256') 'HS512' => 'sha512', ); if (empty($methods[$method])) { - throw new DomainException('Algorithm not supported'); + throw new \DomainException('Algorithm not supported'); } return hash_hmac($methods[$method], $msg, $key, true); } @@ -122,7 +114,7 @@ public static function sign($msg, $key, $method = 'HS256') * @param string $input JSON string * * @return object Object representation of JSON string - * @throws DomainException Provided string was invalid JSON + * @throws \DomainException Provided string was invalid JSON */ public static function jsonDecode($input) { @@ -130,7 +122,7 @@ public static function jsonDecode($input) if (function_exists('json_last_error') && $errno = json_last_error()) { JWT::_handleJsonError($errno); } else if ($obj === null && $input !== 'null') { - throw new DomainException('Null result with non-null input'); + throw new \DomainException('Null result with non-null input'); } return $obj; } @@ -141,7 +133,7 @@ public static function jsonDecode($input) * @param object|array $input A PHP object or array * * @return string JSON representation of the PHP object or array - * @throws DomainException Provided object could not be encoded to valid JSON + * @throws \DomainException Provided object could not be encoded to valid JSON */ public static function jsonEncode($input) { @@ -149,7 +141,7 @@ public static function jsonEncode($input) if (function_exists('json_last_error') && $errno = json_last_error()) { JWT::_handleJsonError($errno); } else if ($json === 'null' && $input !== null) { - throw new DomainException('Null result with non-null input'); + throw new \DomainException('Null result with non-null input'); } return $json; } @@ -188,6 +180,7 @@ public static function urlsafeB64Encode($input) * * @param int $errno An error number from json_last_error() * + * @throws \DomainException * @return void */ private static function _handleJsonError($errno) @@ -197,7 +190,7 @@ private static function _handleJsonError($errno) JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' ); - throw new DomainException( + throw new \DomainException( isset($messages[$errno]) ? $messages[$errno] : 'Unknown JSON error: ' . $errno diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..993e73b0 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + + ./test/JWT/ + + + + + + ./lib/JWT/ + + + + + + + + + \ No newline at end of file diff --git a/test/JWT/Test/Authentication/JWTTest.php b/test/JWT/Test/Authentication/JWTTest.php new file mode 100755 index 00000000..41241ab0 --- /dev/null +++ b/test/JWT/Test/Authentication/JWTTest.php @@ -0,0 +1,46 @@ +assertEquals(JWT::decode($msg, 'my_key'), 'abc'); + } + + public function testDecodeFromPython() + { + $msg = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg.E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg'; + $this->assertEquals( + JWT::decode($msg, 'my_key'), + '*:http://application/clicky?blah=1.23&f.oo=456 AC000 123' + ); + } + + public function testUrlSafeCharacters() + { + $encoded = JWT::encode('f?', 'a'); + $this->assertEquals('f?', JWT::decode($encoded, 'a')); + } + + /** + * @expectedException \DomainException + */ + public function testMalformedUtf8StringsFail() + { + \PHPUnit_Framework_Error_Warning::$enabled = false; + @JWT::encode(pack('c', 128), 'a'); + } + + /** + * @expectedException \DomainException + */ + public function testMalformedJsonThrowsException() + { + JWT::jsonDecode('this is not valid JSON string'); + } +} diff --git a/tests/JWTTest.php b/tests/JWTTest.php deleted file mode 100644 index db50ee61..00000000 --- a/tests/JWTTest.php +++ /dev/null @@ -1,35 +0,0 @@ -assertEquals(JWT::decode($msg, 'my_key'), 'abc'); - } - - function testDecodeFromPython() { - $msg = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg.E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg'; - $this->assertEquals( - JWT::decode($msg, 'my_key'), - '*:http://application/clicky?blah=1.23&f.oo=456 AC000 123' - ); - } - - function testUrlSafeCharacters() { - $encoded = JWT::encode('f?', 'a'); - $this->assertEquals('f?', JWT::decode($encoded, 'a')); - } - - function testMalformedUtf8StringsFail() { - $this->setExpectedException('DomainException'); - JWT::encode(pack('c', 128), 'a'); - } - - function testMalformedJsonThrowsException() { - $this->setExpectedException('DomainException'); - JWT::jsonDecode('this is not valid JSON string'); - } -} - -?>