diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c682f861 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +* text=auto + +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/phpunit.xml.dist export-ignore +/run-tests.sh export-ignore diff --git a/.gitignore b/.gitignore index b1a05b0b..cc979c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ phpunit.phar phpunit.phar.asc composer.phar .idea +composer.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index f4543497..71c1227c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,15 +4,15 @@ php: - 5.4 - 5.5 - 5.6 - - 7 + - 7.0 + - 7.1 + - 7.2 - hhvm +matrix: + allow_failures: + - php: hhvm sudo: false -before_script: - - composer self-update - - composer global require "fxp/composer-asset-plugin:*" - - composer update - - composer info --installed - -script: phpunit -c phpunit.xml.dist \ No newline at end of file +before_script: composer install +script: phpunit diff --git a/README.md b/README.md index 55e8e02f..4d18cb7f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ [![Build Status](https://travis-ci.org/fproject/php-jwt.png?branch=master)](https://travis-ci.org/fproject/php-jwt) [![Latest Stable Version](https://poser.pugx.org/fproject/php-jwt/v/stable)](https://packagist.org/packages/fproject/php-jwt) -[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/fproject/php-jwt) +[![Total Downloads](https://poser.pugx.org/fproject/php-jwt/downloads)](https://packagist.org/packages/fproject/php-jwt) [![License](https://poser.pugx.org/fproject/php-jwt/license)](https://packagist.org/packages/fproject/php-jwt) PHP-JWT ======= -PHP library to encode and decode JSON Web Tokens (JWT). Support several key types including JWK. Conform to the [current spec](http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06) +PHP library to encode and decode JSON Web Tokens (JWT). Support several key types including JWK. Conform to the [current spec](https://tools.ietf.org/html/rfc7519). Installation ------------ @@ -58,17 +58,78 @@ $decoded_array = (array) $decoded; JWT::$leeway = 60; // $leeway in seconds $decoded = JWT::decode($jwt, $key, array('HS256')); +?> +``` +Example with RS256 (openssl) +---------------------------- +```php + "example.org", + "aud" => "example.com", + "iat" => 1356999524, + "nbf" => 1357000000 +); + +$jwt = JWT::encode($token, $privateKey, 'RS256'); +echo "Encode:\n" . print_r($jwt, true) . "\n"; + +$decoded = JWT::decode($jwt, $publicKey, array('RS256')); + +/* + NOTE: This will now be an object instead of an associative array. To get + an associative array, you will need to cast it as such: +*/ + +$decoded_array = (array) $decoded; +echo "Decode:\n" . print_r($decoded_array, true) . "\n"; ?> ``` Changelog --------- + +#### 5.0.0 / 2018-03-21 + - Update to 5.0.0 from upstream + +#### 4.0.0 / 2016-08-10 + - Update to 4.0.0 from upstream + #### 3.0.3 / 2015-11-05 -- Minimum PHP version updated from `5.3.0` to `5.4.0`. -- Add JWK support + - Minimum PHP version updated from `5.3.0` to `5.4.0`. + - Add JWK support #### 3.0.0 / 2015-07-22 -- Original features from firebase/php-jwt repository + - Original features from firebase/php-jwt repository Tests @@ -84,6 +145,12 @@ Time: 0 seconds, Memory: 2.50Mb OK (5 tests, 5 assertions) ``` +New Lines in private keys +----- + +If your private key contains `\n` characters, be sure to wrap it in double quotes `""` +and not single quotes `''` in order to properly interpret the escaped characters. + License ------- [3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause). diff --git a/composer.json b/composer.json index 5b52468a..e25cb490 100644 --- a/composer.json +++ b/composer.json @@ -28,5 +28,7 @@ "Firebase\\JWT\\": "src" } }, - "minimum-stability": "dev" + "require-dev": { + "phpunit/phpunit": "4.8.36" + } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 7ad0cb8e..00000000 --- a/composer.lock +++ /dev/null @@ -1,1058 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "18867f3a3b90fcdf289d47ec125a6b94", - "packages": [], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14 21:17:01" - }, - { - "name": "myclabs/deep-copy", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "95d662954e06000cdf63ec9c9f0a6c598d9c5eb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/95d662954e06000cdf63ec9c9f0a6c598d9c5eb9", - "reference": "95d662954e06000cdf63ec9c9f0a6c598d9c5eb9", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2015-07-19 19:57:13" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2015-02-03 12:10:50" - }, - { - "name": "phpspec/prophecy", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "4f9b1eaf0a7da77c362f8d91cbc68ab1f4718d62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4f9b1eaf0a7da77c362f8d91cbc68ab1f4718d62", - "reference": "4f9b1eaf0a7da77c362f8d91cbc68ab1f4718d62", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "phpdocumentor/reflection-docblock": "~2.0", - "sebastian/comparator": "~1.1" - }, - "require-dev": { - "phpspec/phpspec": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com/" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2015-09-22 14:49:23" - }, - { - "name": "phpunit/php-code-coverage", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "12259bb1352612df9ec24048714a3bedafe79674" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12259bb1352612df9ec24048714a3bedafe79674", - "reference": "12259bb1352612df9ec24048714a3bedafe79674", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~5" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2015-09-24 07:56:07" - }, - { - "name": "phpunit/php-file-iterator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2015-06-21 13:08:43" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21 13:50:34" - }, - { - "name": "phpunit/php-timer", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2015-06-21 08:01:12" - }, - { - "name": "phpunit/php-token-stream", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cab6c6fefee93d7b7c3a01292a0fe0884ea66644", - "reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2015-09-23 14:46:55" - }, - { - "name": "phpunit/phpunit", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b3db8bc29009cbd788cd827d7376a5e8018243ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b3db8bc29009cbd788cd827d7376a5e8018243ce", - "reference": "b3db8bc29009cbd788cd827d7376a5e8018243ce", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "myclabs/deep-copy": "~1.3", - "php": ">=7.0", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~3.0", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": ">=1.0.6", - "phpunit/phpunit-mock-objects": ">=3.0", - "sebastian/comparator": "~1.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2015-09-27 08:37:11" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "4f526b7e2c42cacf32c86e1e0c9ab9d3b24273cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/4f526b7e2c42cacf32c86e1e0c9ab9d3b24273cf", - "reference": "4f526b7e2c42cacf32c86e1e0c9ab9d3b24273cf", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.6", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2015-09-02 07:30:58" - }, - { - "name": "sebastian/comparator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2015-07-26 15:48:44" - }, - { - "name": "sebastian/diff", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "6899b3e33bfbd386d88b5eea5f65f563e8793051" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6899b3e33bfbd386d88b5eea5f65f563e8793051", - "reference": "6899b3e33bfbd386d88b5eea5f65f563e8793051", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "http://www.github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2015-06-22 14:15:55" - }, - { - "name": "sebastian/environment", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44", - "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2015-08-03 06:14:51" - }, - { - "name": "sebastian/exporter", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "f88f8936517d54ae6d589166810877fb2015d0a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f88f8936517d54ae6d589166810877fb2015d0a2", - "reference": "f88f8936517d54ae6d589166810877fb2015d0a2", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2015-08-09 04:23:41" - }, - { - "name": "sebastian/global-state", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23af31f402993cfd94e99cbc4b782e9a78eb0e97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23af31f402993cfd94e99cbc4b782e9a78eb0e97", - "reference": "23af31f402993cfd94e99cbc4b782e9a78eb0e97", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-06-21 15:11:22" - }, - { - "name": "sebastian/recursion-context", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "994d4a811bafe801fb06dccbee797863ba2792ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/994d4a811bafe801fb06dccbee797863ba2792ba", - "reference": "994d4a811bafe801fb06dccbee797863ba2792ba", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-06-21 08:04:50" - }, - { - "name": "sebastian/resource-operations", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" - }, - { - "name": "symfony/yaml", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "b68154f3ee23d8294936433fd31725a83bd02f71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/b68154f3ee23d8294936433fd31725a83bd02f71", - "reference": "b68154f3ee23d8294936433fd31725a83bd02f71", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.8|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com/", - "time": "2015-09-14 14:15:24" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.3.0" - }, - "platform-dev": [] -} diff --git a/run-tests.sh b/run-tests.sh index d37c30fd..c4bb9348 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash gpg --fingerprint D8406D0D82947747293778314AA394086372C20A if [ $? -ne 0 ]; then diff --git a/src/JWK.php b/src/JWK.php index cf3cc930..8eecb73f 100644 --- a/src/JWK.php +++ b/src/JWK.php @@ -1,6 +1,7 @@ $v) - { - if(!is_string($k)) - { - if(is_array($v) && isset($v['kid'])) + foreach ($source as $k => $v) { + if (!is_string($k)) { + if (is_array($v) && isset($v['kid'])) $k = $v['kid']; - elseif(is_object($v) && property_exists($v,'kid')) + elseif (is_object($v) && property_exists($v, 'kid')) $k = $v->{'kid'}; } - $v = self::parseKey($v); - $keys[$k] = $v; + try { + $v = self::parseKey($v); + $keys[$k] = $v; + } catch (UnexpectedValueException $e) { + //Do nothing + } } - + } + if (0 < count($keys)) { return $keys; } - throw new UnexpectedValueException('Failed to parse JWK'); } @@ -67,19 +66,17 @@ public static function parseKeySet($source) */ public static function parseKey($source) { - if(!is_array($source)) + if (!is_array($source)) $source = (array)$source; - if(!empty($source) && isset($source['kty']) && isset($source['n']) && isset($source['e'])) - { - switch ($source['kty']) - { + if (!empty($source) && isset($source['kty']) && isset($source['n']) && isset($source['e'])) { + switch ($source['kty']) { case 'RSA': if (array_key_exists('d', $source)) throw new UnexpectedValueException('Failed to parse JWK: RSA private key is not supported'); $pem = self::createPemFromModulusAndExponent($source['n'], $source['e']); $pKey = openssl_pkey_get_public($pem); - if($pKey !== false) + if ($pKey !== false) return $pKey; break; default: diff --git a/src/JWT.php b/src/JWT.php index 1456672d..8a54ebd0 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -8,7 +8,7 @@ /** * JSON Web Token implementation, based on this spec: - * http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06 + * https://tools.ietf.org/html/rfc7519 * * PHP version 5 * @@ -30,25 +30,34 @@ class JWT */ public static $leeway = 0; + /** + * Allow the current timestamp to be specified. + * Useful for fixing a value within unit testing. + * + * Will default to PHP time() value if null. + */ + public static $timestamp = null; + public static $supported_algs = array( 'HS256' => array('hash_hmac', 'SHA256'), 'HS512' => array('hash_hmac', 'SHA512'), 'HS384' => array('hash_hmac', 'SHA384'), 'RS256' => array('openssl', 'SHA256'), + 'RS384' => array('openssl', 'SHA384'), + 'RS512' => array('openssl', 'SHA512'), ); /** * Decodes a JWT string into a PHP object. * - * @param string $jwt The JWT - * @param string|array|null $key The key, or map of keys. - * If the algorithm used is asymmetric, this is the public key - * @param array $allowed_algs List of supported verification algorithms - * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * @param string $jwt The JWT + * @param string|array $key The key, or map of keys. + * If the algorithm used is asymmetric, this is the public key + * @param array $allowed_algs List of supported verification algorithms + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' * * @return object The JWT's payload as a PHP object * - * @throws DomainException Algorithm was not provided * @throws UnexpectedValueException Provided JWT was invalid * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' @@ -58,8 +67,10 @@ class JWT * @uses jsonDecode * @uses urlsafeB64Decode */ - public static function decode($jwt, $key, $allowed_algs = array()) + public static function decode($jwt, $key, array $allowed_algs = array()) { + $timestamp = is_null(static::$timestamp) ? time() : static::$timestamp; + if (empty($key)) { throw new InvalidArgumentException('Key may not be empty'); } @@ -68,39 +79,43 @@ public static function decode($jwt, $key, $allowed_algs = array()) throw new UnexpectedValueException('Wrong number of segments'); } list($headb64, $bodyb64, $cryptob64) = $tks; - if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) { + if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) { throw new UnexpectedValueException('Invalid header encoding'); } - if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) { + if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) { throw new UnexpectedValueException('Invalid claims encoding'); } - $sig = JWT::urlsafeB64Decode($cryptob64); - + if (false === ($sig = static::urlsafeB64Decode($cryptob64))) { + throw new UnexpectedValueException('Invalid signature encoding'); + } if (empty($header->alg)) { - throw new DomainException('Empty algorithm'); + throw new UnexpectedValueException('Empty algorithm'); } - if (empty(self::$supported_algs[$header->alg])) { - throw new DomainException('Algorithm not supported'); + if (empty(static::$supported_algs[$header->alg])) { + throw new UnexpectedValueException('Algorithm not supported'); } - if (!is_array($allowed_algs) || !in_array($header->alg, $allowed_algs)) { - throw new DomainException('Algorithm not allowed'); + if (!in_array($header->alg, $allowed_algs)) { + throw new UnexpectedValueException('Algorithm not allowed'); } if (is_array($key) || $key instanceof \ArrayAccess) { if (isset($header->kid)) { + if (!isset($key[$header->kid])) { + throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key'); + } $key = $key[$header->kid]; } else { - throw new DomainException('"kid" empty, unable to lookup correct key'); + throw new UnexpectedValueException('"kid" empty, unable to lookup correct key'); } } // Check the signature - if (!JWT::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) { + if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) { throw new SignatureInvalidException('Signature verification failed'); } // Check if the nbf if it is defined. This is the time that the // token can actually be used. If it's not yet that time, abort. - if (isset($payload->nbf) && $payload->nbf > (time() + self::$leeway)) { + if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) { throw new BeforeValidException( 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf) ); @@ -109,14 +124,14 @@ public static function decode($jwt, $key, $allowed_algs = array()) // Check that this token has been created before 'now'. This prevents // using tokens that have been created for later use (and haven't // correctly used the nbf claim). - if (isset($payload->iat) && $payload->iat > (time() + self::$leeway)) { + if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) { throw new BeforeValidException( 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat) ); } // Check if this token has expired. - if (isset($payload->exp) && (time() - self::$leeway) >= $payload->exp) { + if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) { throw new ExpiredException('Expired token'); } @@ -131,6 +146,7 @@ public static function decode($jwt, $key, $allowed_algs = array()) * If the algorithm used is asymmetric, this is the private key * @param string $alg The signing algorithm. * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * @param mixed $keyId * @param array $head An array with header elements to attach * * @return string A signed JWT @@ -148,12 +164,12 @@ public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $he $header = array_merge($head, $header); } $segments = array(); - $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header)); - $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload)); + $segments[] = static::urlsafeB64Encode(static::jsonEncode($header)); + $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload)); $signing_input = implode('.', $segments); - $signature = JWT::sign($signing_input, $key, $alg); - $segments[] = JWT::urlsafeB64Encode($signature); + $signature = static::sign($signing_input, $key, $alg); + $segments[] = static::urlsafeB64Encode($signature); return implode('.', $segments); } @@ -172,10 +188,10 @@ public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $he */ public static function sign($msg, $key, $alg = 'HS256') { - if (empty(self::$supported_algs[$alg])) { + if (empty(static::$supported_algs[$alg])) { throw new DomainException('Algorithm not supported'); } - list($function, $algorithm) = self::$supported_algs[$alg]; + list($function, $algorithm) = static::$supported_algs[$alg]; switch($function) { case 'hash_hmac': return hash_hmac($algorithm, $msg, $key, true); @@ -205,32 +221,36 @@ public static function sign($msg, $key, $alg = 'HS256') */ private static function verify($msg, $signature, $key, $alg) { - if (empty(self::$supported_algs[$alg])) { + if (empty(static::$supported_algs[$alg])) { throw new DomainException('Algorithm not supported'); } - list($function, $algorithm) = self::$supported_algs[$alg]; + list($function, $algorithm) = static::$supported_algs[$alg]; switch($function) { case 'openssl': $success = openssl_verify($msg, $signature, $key, $algorithm); - if (!$success) { - throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string()); - } else { - return $signature; + if ($success === 1) { + return true; + } elseif ($success === 0) { + return false; } + // returns 1 on success, 0 on failure, -1 on error. + throw new DomainException( + 'OpenSSL error: ' . openssl_error_string() + ); case 'hash_hmac': default: $hash = hash_hmac($algorithm, $msg, $key, true); if (function_exists('hash_equals')) { return hash_equals($signature, $hash); } - $len = min(self::safeStrlen($signature), self::safeStrlen($hash)); + $len = min(static::safeStrlen($signature), static::safeStrlen($hash)); $status = 0; for ($i = 0; $i < $len; $i++) { $status |= (ord($signature[$i]) ^ ord($hash[$i])); } - $status |= (self::safeStrlen($signature) ^ self::safeStrlen($hash)); + $status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash)); return ($status === 0); } @@ -264,7 +284,7 @@ public static function jsonDecode($input) } if (function_exists('json_last_error') && $errno = json_last_error()) { - JWT::handleJsonError($errno); + static::handleJsonError($errno); } elseif ($obj === null && $input !== 'null') { throw new DomainException('Null result with non-null input'); } @@ -284,7 +304,7 @@ public static function jsonEncode($input) { $json = json_encode($input); if (function_exists('json_last_error') && $errno = json_last_error()) { - JWT::handleJsonError($errno); + static::handleJsonError($errno); } elseif ($json === 'null' && $input !== null) { throw new DomainException('Null result with non-null input'); } @@ -331,8 +351,10 @@ private static function handleJsonError($errno) { $messages = array( JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', - JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3 ); throw new DomainException( isset($messages[$errno]) diff --git a/tests/JWTTest.php b/tests/JWTTest.php index 1402182c..f83adff4 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -1,9 +1,13 @@ setExpectedException('Firebase\JWT\ExpiredException'); JWT::decode($msg, $key, array('RS256')); } @@ -36,10 +38,23 @@ public function testDecodeByJWKKeySet() $jsKey = '{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"s1","n":"kWp2zRA23Z3vTL4uoe8kTFptxBVFunIoP4t_8TDYJrOb7D1iZNDXVeEsYKp6ppmrTZDAgd-cNOTKLd4M39WJc5FN0maTAVKJc7NxklDeKc4dMe1BGvTZNG4MpWBo-taKULlYUu0ltYJuLzOjIrTHfarucrGoRWqM0sl3z2-fv9k"}]}'; $key = JWK::parseKeySet($jsKey); - $msg = 'eyJraWQiOiJzMSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJYcEFCeEpnVXhLN2JKdnVnRGFXaXlYLWF6aDliSlJ4OGU1dGJzdjVZblpRIiwic2NwIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSIsInJzLXBrLW1haW4iLCJycy1way1zbyIsInJzLXBrLWlzc3VlIiwicnMtcGstd2ViIl0sImNsbSI6WyJwcm9qZWN0R3JvdXBzIiwiITV2OEgiXSwiaXNzIjoiaHR0cDpcL1wvaWQucHJvamVjdGtpdC5uZXQiLCJleHAiOjE0NzYyNDgyMzMsImNpZCI6ImNpZC1way13ZWIifQ.cxkukSfQ9YrvLr8X-0RV_00FRoSvnA1er-6qvfpgIKjShjUfjga4T-wCv-KrVpYqQAxTdDZZJNwiDo3oLuqSwsvBmwT1Wyt1wce9GLAd3MSW9KtHnygGwqtdbP3taWieQrpgNNlQTJHex-XqlkVR722pxgPjtj-96IV8WPC0vek'; + $msg = 'eyJraWQiOiJzMSIsImFsZyI6IlJTMjU2In0.eyJzY3AiOlsib3BlbmlkIiwiZW1haWwiLCJwcm9maWxlIiwiYWFzIl0sInN1YiI6InRVQ1l0bmZJQlBXY3JTSmY0eUJmdk4xa3d3NEtHY3kzTElQazFHVnpzRTAiLCJjbG0iOlsiITV2OEgiXSwiaXNzIjoiaHR0cDpcL1wvMTMwLjIxMS4yNDMuMTE0OjgwODBcL2MyaWQiLCJleHAiOjE0NDExMjY1MzksInVpcCI6eyJncm91cHMiOlsiYWRtaW4iLCJhdWRpdCJdfSwiY2lkIjoicGstb2lkYy0wMSJ9.PvYrnf3k1Z0wgRwCgq0WXKaoIv1hHtzBFO5cGfCs6bl4suc6ilwCWmJqRxGYkU2fNTGyMOt3OUnnBEwl6v5qN6jv7zbkVAVKVvbQLxhHC2nXe3izvoCiVaMEH6hE7VTWwnPbX_qO72mCwTizHTJTZGLOsyXLYM6ctdOMf7sFPTI'; + $this->setExpectedException('Firebase\JWT\ExpiredException'); + $payload = JWT::decode($msg, $key, array('RS256')); + $this->assertEquals("tUCYtnfIBPWcrSJf4yBfvN1kww4KGcy3LIPk1GVzsE0",$payload->sub); + $this->assertEquals(1441126539,$payload->exp); + } + + public function testDecodeByMultiJWKKeySet() + { + $jsKey = '{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"CXup","n":"hrwD-lc-IwzwidCANmy4qsiZk11yp9kHykOuP0yOnwi36VomYTQVEzZXgh2sDJpGgAutdQudgwLoV8tVSsTG9SQHgJjH9Pd_9V4Ab6PANyZNG6DSeiq1QfiFlEP6Obt0JbRB3W7X2vkxOVaNoWrYskZodxU2V0ogeVL_LkcCGAyNu2jdx3j0DjJatNVk7ystNxb9RfHhJGgpiIkO5S3QiSIVhbBKaJHcZHPF1vq9g0JMGuUCI-OTSVg6XBkTLEGw1C_R73WD_oVEBfdXbXnLukoLHBS11p3OxU7f4rfxA_f_72_UwmWGJnsqS3iahbms3FkvqoL9x_Vj3GhuJSf97Q"},{"kty":"EC","use":"sig","crv":"P-256","kid":"yGvt","x":"pvgdqM3RCshljmuCF1D2Ez1w5ei5k7-bpimWLPNeEHI","y":"JSmUhbUTqiFclVLEdw6dz038F7Whw4URobjXbAReDuM"},{"kty":"EC","use":"sig","crv":"P-384","kid":"9nHY","x":"JPKhjhE0Bj579Mgj3Cn3ERGA8fKVYoGOaV9BPKhtnEobphf8w4GSeigMesL-038W","y":"UbJa1QRX7fo9LxSlh7FOH5ABT5lEtiQeQUcX9BW0bpJFlEVGqwec80tYLdOIl59M"},{"kty":"EC","use":"sig","crv":"P-521","kid":"tVzS","x":"AZgkRHlIyNQJlPIwTWdHqouw41k9dS3GJO04BDEnJnd_Dd1owlCn9SMXA-JuXINn4slwbG4wcECbctXb2cvdGtmn","y":"AdBC6N9lpupzfzcIY3JLIuc8y8MnzV-ItmzHQcC5lYWMTbuM9NU_FlvINeVo8g6i4YZms2xFB-B0VVdaoF9kUswC"}]}'; + $key = JWK::parseKeySet($jsKey); + + $msg = 'eyJraWQiOiJDWHVwIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJmOGI2N2NjNDYwMzA3NzdlZmQ4YmNlNmMxYmZlMjljNmMwZjgxOGVjIiwic2NwIjpbIm9wZW5pZCIsIm5hbWUiLCJwcm9maWxlIiwicGljdHVyZSIsImVtYWlsIiwicnMtcGstbWFpbiIsInJzLXBrLXNvIiwicnMtcGstaXNzdWUiLCJycy1way13ZWIiXSwiY2xtIjpbIiE1djhIIl0sImlzcyI6Imh0dHBzOlwvXC9pZC5wcm9qZWN0a2l0Lm5ldFwvYXV0aGVudGljYXRlIiwiZXhwIjoxNDkyMjI4MzM2LCJpYXQiOjE0OTEzNjQzMzYsImNpZCI6ImNpZC1way13ZWIifQ.KW1K-72bMtiNwvyYBgffG6VaG6I59cELGYQR8M2q7HA8dmzliu6QREJrqyPtwW_rDJZbsD3eylvkRinK9tlsMXCOfEJbxLdAC9b4LKOsnsbuXXwsJHWkFG0a7osdW0ZpXJDoMFlO1aosxRGMkaqhf1wIkvQ5PM_EB08LJv7oz64Antn5bYaoajwgvJRl7ChatRDn9Sx5UIElKD1BK4Uw5WdrZwBlWdWZVNCSFhy4F6SdZvi3OBlXzluDwq61RC-pl2iivilJNljYWVrthHDS1xdtaVz4oteHW13-IS7NNEz6PVnzo5nyoPWMAB4JlRnxcfOFTTUqOA2mX5Csg0UpdQ'; + $this->setExpectedException('Firebase\JWT\ExpiredException'); $payload = JWT::decode($msg, $key, array('RS256')); - $this->assertEquals("XpABxJgUxK7bJvugDaWiyX-azh9bJRx8e5tbsv5YnZQ",$payload->sub); - $this->assertEquals(1476248233,$payload->exp); + $this->assertEquals("f8b67cc46030777efd8bce6c1bfe29c6c0f818ec",$payload->sub); + $this->assertEquals(1492228336,$payload->exp); } public function testUrlSafeCharacters() @@ -227,24 +242,14 @@ public function testEmptyKeyFails() public function testRSEncodeDecode() { - $privKey = openssl_pkey_new(array( - //'config'=>'C:/wamp/bin/apache/Apache2.4.4/conf/openssl.cnf',//Remove this line when test on travis-ci.org - 'digest_alg' => 'sha512', - 'private_key_bits' => 4096, + $privKey = openssl_pkey_new(array('digest_alg' => 'sha256', + 'private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA)); - if($privKey === false) - { - $s = openssl_error_string(); - $this->fail("Cannot create private key: $s"); - } - else - { - $msg = JWT::encode('abc', $privKey, 'RS256'); - $pubKey = openssl_pkey_get_details($privKey); - $pubKey = $pubKey['key']; - $decoded = JWT::decode($msg, $pubKey, array('RS256')); - $this->assertEquals($decoded, 'abc'); - } + $msg = JWT::encode('abc', $privKey, 'RS256'); + $pubKey = openssl_pkey_get_details($privKey); + $pubKey = $pubKey['key']; + $decoded = JWT::decode($msg, $pubKey, array('RS256')); + $this->assertEquals($decoded, 'abc'); } public function testKIDChooser() @@ -266,28 +271,28 @@ public function testArrayAccessKIDChooser() public function testNoneAlgorithm() { $msg = JWT::encode('abc', 'my_key'); - $this->setExpectedException('DomainException'); + $this->setExpectedException('UnexpectedValueException'); JWT::decode($msg, 'my_key', array('none')); } public function testIncorrectAlgorithm() { $msg = JWT::encode('abc', 'my_key'); - $this->setExpectedException('DomainException'); + $this->setExpectedException('UnexpectedValueException'); JWT::decode($msg, 'my_key', array('RS256')); } public function testMissingAlgorithm() { $msg = JWT::encode('abc', 'my_key'); - $this->setExpectedException('DomainException'); + $this->setExpectedException('UnexpectedValueException'); JWT::decode($msg, 'my_key'); } public function testAdditionalHeaders() { $msg = JWT::encode('abc', 'my_key', 'HS256', null, array('cty' => 'test-eit;v=1')); - $this->assertEquals(JWT::decode($msg, 'my_key', array('HS256')), 'abc'); + $this->assertEquals(JWT::decode($msg, 'my_key', array('HS256')), 'abc'); } public function testInvalidSegmentCount() @@ -295,4 +300,31 @@ public function testInvalidSegmentCount() $this->setExpectedException('UnexpectedValueException'); JWT::decode('brokenheader.brokenbody', 'my_key', array('HS256')); } + + public function testInvalidSignatureEncoding() + { + $msg = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwibmFtZSI6ImZvbyJ9.Q4Kee9E8o0Xfo4ADXvYA8t7dN_X_bU9K5w6tXuiSjlUxx"; + $this->setExpectedException('UnexpectedValueException'); + JWT::decode($msg, 'secret', array('HS256')); + } + + public function testVerifyError() + { + $this->setExpectedException('DomainException'); + $pkey = openssl_pkey_new(array('private_key_bits' => 1024)); + $msg = JWT::encode('abc', $pkey, 'RS256'); + self::$opensslVerifyReturnValue = -1; + JWT::decode($msg, $pkey, array('RS256')); + } +} + +/* + * Allows the testing of openssl_verify with an error return value + */ +function openssl_verify($msg, $signature, $key, $algorithm) +{ + if (null !== JWTTest::$opensslVerifyReturnValue) { + return JWTTest::$opensslVerifyReturnValue; + } + return \openssl_verify($msg, $signature, $key, $algorithm); }