├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Algorithm │ ├── AlgorithmInterface.php │ ├── AsymmetricInterface.php │ ├── EcdSa.php │ ├── Es256.php │ ├── Es384.php │ ├── Es512.php │ ├── Hmac.php │ ├── Hs256.php │ ├── Hs384.php │ ├── Hs512.php │ ├── None.php │ ├── Ps256.php │ ├── Ps384.php │ ├── Ps512.php │ ├── README.md │ ├── Rs256.php │ ├── Rs384.php │ ├── Rs512.php │ ├── RsaSsaPkcs.php │ ├── RsaSsaPss.php │ └── SymmetricInterface.php ├── Claim │ ├── AbstractClaim.php │ ├── Audience.php │ ├── ClaimInterface.php │ ├── DateValueClaim.php │ ├── Expiration.php │ ├── Factory.php │ ├── IssuedAt.php │ ├── Issuer.php │ ├── JwtId.php │ ├── NotBefore.php │ ├── PrivateClaim.php │ ├── PublicClaim.php │ └── Subject.php ├── Encoding │ ├── Base64.php │ └── EncoderInterface.php ├── Encryption │ ├── AbstractEncryption.php │ ├── Asymmetric.php │ ├── EncryptionInterface.php │ ├── Factory.php │ └── Symmetric.php ├── Exception │ ├── ExpiredException.php │ ├── InvalidAudienceException.php │ ├── InvalidIssuerException.php │ ├── InvalidSignatureException.php │ ├── InvalidSubjectException.php │ ├── TooEarlyException.php │ └── VerificationException.php ├── FactoryTrait.php ├── HeaderParameter │ ├── AbstractParameter.php │ ├── Algorithm.php │ ├── ContentType.php │ ├── Critical.php │ ├── Custom.php │ ├── Factory.php │ ├── JsonWebKey.php │ ├── JwkSetUrl.php │ ├── KeyId.php │ ├── ParameterInterface.php │ ├── Type.php │ ├── X509CertificateChain.php │ ├── X509CertificateSha1Thumbprint.php │ ├── X509CertificateSha256Thumbprint.php │ └── X509Url.php ├── Jwt.php ├── Serialization │ ├── Compact.php │ └── SerializerInterface.php ├── Signature │ ├── Jws.php │ ├── README.md │ └── SignerInterface.php ├── Token.php ├── Token │ ├── Header.php │ ├── Payload.php │ ├── PropertyInterface.php │ └── PropertyList.php └── Verification │ ├── AudienceVerifier.php │ ├── Context.php │ ├── EncryptionVerifier.php │ ├── ExpirationVerifier.php │ ├── IssuerVerifier.php │ ├── NotBeforeVerifier.php │ ├── SubjectVerifier.php │ └── VerifierInterface.php └── test ├── Algorithm ├── Es256Test.php ├── Es384Test.php ├── Es512Test.php ├── Hs256Test.php ├── Hs384Test.php ├── Hs512Test.php ├── Ps256Test.php ├── Ps384Test.php ├── Ps512Test.php ├── Rs256Test.php ├── Rs384Test.php └── Rs512Test.php ├── Claim ├── AudienceTest.php ├── ExpirationTest.php ├── FactoryTest.php ├── IssuedAtTest.php ├── IssuerTest.php ├── JwtIdTest.php ├── NotBeforeTest.php ├── PrivateClaimTest.php ├── PublicClaimTest.php └── SubjectTest.php ├── Encoding └── Base64Test.php ├── Encryption ├── AsymmetricTest.php ├── FactoryTest.php ├── SymmetricTest.php └── UnknownAlgorithmStub.php ├── HeaderParameter ├── AlgorithmTest.php ├── ContentTypeTest.php ├── CriticalTest.php ├── CustomTest.php ├── FactoryTest.php ├── JsonWebKeyTest.php ├── JwkSetUrlTest.php ├── KeyIdTest.php ├── TypeTest.php ├── X509CertificateChainTest.php ├── X509CertificateSha1ThumbprintTest.php ├── X509CertificateSha256ThumbprintTest.php └── X509UrlTest.php ├── Serialization └── CompactTest.php ├── Signature └── JwsTest.php ├── Token ├── HeaderStub.php ├── HeaderTest.php ├── PayloadStub.php ├── PayloadTest.php ├── PropertyListStub.php ├── PropertyListTest.php └── PropertyStub.php └── Verification ├── AudienceVerifierTest.php ├── EncryptionVerifierStub.php ├── EncryptionVerifierTest.php ├── ExpirationVerifierTest.php ├── IssuerVerifierTest.php ├── NotBeforeVerifierTest.php └── SubjectVerifierTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor/ 3 | bin 4 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: 3 | code_rating: true 4 | duplication: true 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - "7.0" 4 | - "5.6" 5 | - "5.5" 6 | - "5.4" 7 | - hhvm 8 | install: composer install 9 | script: ./bin/phpunit 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Malcolm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An implementation of the [JSON Web Token (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30) draft in PHP. See [jwt.io](http://jwt.io/) for more information on JWT. 2 | 3 | [![Build Status](https://travis-ci.org/emarref/jwt.svg?branch=master)](https://travis-ci.org/emarref/jwt) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/emarref/jwt/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/emarref/jwt/?branch=master) 4 | 5 | Features include: 6 | 7 | - Token serialization 8 | - Token deserialization 9 | - Token verification 10 | - `aud`, `exp`, `iss`, `nbf`, `sub` claims are verified 11 | - Symmetric Encryption 12 | - `NONE`, `HS256`, `HS384`, `HS512` algorithms supported 13 | - Asymmetric Encryption 14 | - `RS256`, `RS384`, `RS512` algorithms supported 15 | - `ES256`, `ES384`, `ES512`, `PS256`, `PS384`, `PS512` algorithms are planned 16 | 17 | > :warning: Versions of this library up to and including v1.0.2 are susceptible to timing attacks when using Symmetric encryption. See [#20](https://github.com/emarref/jwt/pull/20) for more information. Please update to >= v1.0.3 as soon as possible to address this vulnerability. 18 | 19 | This library is not susceptible to a common [encryption vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). 20 | 21 | ## Installation 22 | 23 | ``` 24 | composer require emarref/jwt 25 | ``` 26 | 27 | ## Usage 28 | 29 | Create an instance of the `Emarref\Jwt\Token` class, then configure it. 30 | 31 | ```php 32 | use Emarref\Jwt\Claim; 33 | 34 | $token = new Emarref\Jwt\Token(); 35 | 36 | // Standard claims are supported 37 | $token->addClaim(new Claim\Audience(['audience_1', 'audience_2'])); 38 | $token->addClaim(new Claim\Expiration(new \DateTime('30 minutes'))); 39 | $token->addClaim(new Claim\IssuedAt(new \DateTime('now'))); 40 | $token->addClaim(new Claim\Issuer('your_issuer')); 41 | $token->addClaim(new Claim\JwtId('your_id')); 42 | $token->addClaim(new Claim\NotBefore(new \DateTime('now'))); 43 | $token->addClaim(new Claim\Subject('your_subject')); 44 | 45 | // Custom claims are supported 46 | $token->addClaim(new Claim\PublicClaim('claim_name', 'claim_value')); 47 | $token->addClaim(new Claim\PrivateClaim('claim_name', 'claim_value')); 48 | ``` 49 | 50 | To use a token, create a JWT instance. 51 | 52 | ```php 53 | $jwt = new Emarref\Jwt\Jwt(); 54 | ``` 55 | 56 | To retrieve the encoded token for transfer, call the `serialize()` method. 57 | 58 | ```php 59 | $algorithm = new Emarref\Jwt\Algorithm\None(); 60 | $encryption = Emarref\Jwt\Encryption\Factory::create($algorithm); 61 | $serializedToken = $jwt->serialize($token, $encryption); 62 | ``` 63 | 64 | The `$serializedToken` variable now contains the unencrypted base64 encoded string representation of your token. To encrypt a token, pass an instance of `Emarref\Jwt\Encryption\EncryptionInterface` to the `serialize()` method as the second argument. 65 | 66 | ```php 67 | $algorithm = new Emarref\Jwt\Algorithm\Hs256('verysecret'); 68 | $encryption = Emarref\Jwt\Encryption\Factory::create($algorithm); 69 | $serializedToken = $jwt->serialize($token, $encryption); 70 | ``` 71 | 72 | An example of using Rs256 encryption with a key pair can be found in the wiki - [Using RS256 Encryption](https://github.com/emarref/jwt/wiki/Using-RS256-Encryption). 73 | 74 | To use a serialized token, first deserialize it into a `Emarref\Jwt\Token` object using a `Jwt` instance. 75 | 76 | ```php 77 | $token = $jwt->deserialize($serializedToken); 78 | ``` 79 | 80 | To verify a token's claims, first set up the context that should be used to verify the token against. Encryption is the only required verification. 81 | 82 | ```php 83 | $context = new Emarref\Jwt\Verification\Context($encryption); 84 | $context->setAudience('audience_1'); 85 | $context->setIssuer('your_issuer'); 86 | ``` 87 | 88 | Then use the `verify()` method on a `Jwt` instance. 89 | 90 | ```php 91 | try { 92 | $jwt->verify($token, $context); 93 | } catch (Emarref\Jwt\Exception\VerificationException $e) { 94 | echo $e->getMessage(); 95 | } 96 | ``` 97 | ## Testing 98 | 99 | This library uses PHPUnit for unit testing. Make sure you've run `composer install` then call: 100 | 101 | ``` 102 | ./bin/phpunit ./test 103 | ``` 104 | 105 | ## Further Reading 106 | 107 | - [JSON Web Encryption (JWE)](https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-36) 108 | - [JSON Web Signature (JWS)](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-36) 109 | - [JSON Web Algorithms (JWA)](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36) 110 | - [JSON Web Key (JWK)](https://tools.ietf.org/html/draft-ietf-jose-json-web-key-36) 111 | - [http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) 112 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emarref/jwt", 3 | "description": "A JWT implementation", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Malcolm Fell", 8 | "email": "emarref@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.4" 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "*" 16 | }, 17 | "suggest": { 18 | "ext-openssl": "Enables more token encryption options" 19 | }, 20 | "config": { 21 | "bin-dir": "bin" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Emarref\\Jwt\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Emarref\\Jwt\\": "test/" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 7 | 8 | 9 | vendor 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Algorithm/AlgorithmInterface.php: -------------------------------------------------------------------------------- 1 | secret = $secret; 18 | 19 | $this->ensureSupport(); 20 | } 21 | 22 | /** 23 | * @throws \RuntimeException 24 | */ 25 | private function ensureSupport() 26 | { 27 | $supportedAlgorithms = $this->getSupportedAlgorithms(); 28 | 29 | if (!in_array($this->getAlgorithm(), $supportedAlgorithms)) { 30 | throw new \RuntimeException(sprintf( 31 | 'Encryption algorithm "%s" is not supported on this system.', 32 | $this->getAlgorithm() 33 | )); 34 | } 35 | } 36 | 37 | /** 38 | * @return array 39 | */ 40 | protected function getSupportedAlgorithms() 41 | { 42 | return hash_algos(); 43 | } 44 | 45 | /** 46 | * @param string $value 47 | * @return string 48 | */ 49 | public function compute($value) 50 | { 51 | return hash_hmac($this->getAlgorithm(), $value, $this->secret, true); 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | abstract protected function getAlgorithm(); 58 | } 59 | -------------------------------------------------------------------------------- /src/Algorithm/Hs256.php: -------------------------------------------------------------------------------- 1 | ensureSupport(); 10 | } 11 | 12 | /** 13 | * @throws \RuntimeException 14 | */ 15 | public function ensureSupport() 16 | { 17 | if (!function_exists('openssl_sign')) { 18 | throw new \RuntimeException('Openssl is required to use RSA encryption.'); 19 | } 20 | 21 | $supportedAlgorithms = openssl_get_md_methods(true); 22 | 23 | if (!in_array($this->getAlgorithm(), $supportedAlgorithms)) { 24 | throw new \RuntimeException('Algorithm "%s" is not supported on this system.', $this->getAlgorithm()); 25 | } 26 | } 27 | 28 | /** 29 | * @return array 30 | */ 31 | private function getSslErrors() 32 | { 33 | $messages = []; 34 | 35 | while ($msg = openssl_error_string()) { 36 | $messages[] = $msg; 37 | } 38 | 39 | return $messages; 40 | } 41 | 42 | /** 43 | * @param string $value 44 | * @param string|resource $privateKey 45 | * @return string 46 | */ 47 | public function sign($value, $privateKey) 48 | { 49 | $result = openssl_sign($value, $signature, $privateKey, $this->getAlgorithm()); 50 | 51 | if (false === $result) { 52 | throw new \RuntimeException('Failed to encrypt value. ' . implode("\n", $this->getSslErrors())); 53 | } 54 | 55 | return $signature; 56 | } 57 | 58 | /** 59 | * @param string $value 60 | * @param string $signature 61 | * @param string|resource $publicKey 62 | * @return boolean 63 | */ 64 | public function verify($value, $signature, $publicKey) 65 | { 66 | $result = openssl_verify($value, $signature, $publicKey, $this->getAlgorithm()); 67 | 68 | if ($result === -1) { 69 | throw new \RuntimeException('Failed to verify signature. ' . implode("\n", $this->getSslErrors())); 70 | } 71 | 72 | return (boolean)$result; 73 | } 74 | 75 | /** 76 | * @return integer 77 | */ 78 | abstract protected function getAlgorithm(); 79 | } 80 | -------------------------------------------------------------------------------- /src/Algorithm/RsaSsaPss.php: -------------------------------------------------------------------------------- 1 | setValue($value); 15 | } 16 | 17 | /** 18 | * @return mixed 19 | */ 20 | public function getValue() 21 | { 22 | return $this->value; 23 | } 24 | 25 | /** 26 | * @param mixed 27 | */ 28 | public function setValue($value) 29 | { 30 | $this->value = $value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Claim/Audience.php: -------------------------------------------------------------------------------- 1 | setTimezone(new \DateTimeZone('UTC')); 14 | $value = $value->getTimestamp(); 15 | } 16 | 17 | parent::setValue($value); 18 | } 19 | 20 | /** 21 | * @return int 22 | */ 23 | public function getValue() 24 | { 25 | return parent::getValue(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Claim/Expiration.php: -------------------------------------------------------------------------------- 1 | 'Emarref\Jwt\Claim\Audience', 24 | Expiration::NAME => 'Emarref\Jwt\Claim\Expiration', 25 | IssuedAt::NAME => 'Emarref\Jwt\Claim\IssuedAt', 26 | Issuer::NAME => 'Emarref\Jwt\Claim\Issuer', 27 | JwtId::NAME => 'Emarref\Jwt\Claim\JwtId', 28 | NotBefore::NAME => 'Emarref\Jwt\Claim\NotBefore', 29 | Subject::NAME => 'Emarref\Jwt\Claim\Subject', 30 | ]; 31 | 32 | /** 33 | * @return array 34 | */ 35 | protected function getClassMap() 36 | { 37 | return self::$classMap; 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | protected function getDefaultClass() 44 | { 45 | return self::$privateClaimClass; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Claim/IssuedAt.php: -------------------------------------------------------------------------------- 1 | setName($name); 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public function getName() 34 | { 35 | return $this->name; 36 | } 37 | 38 | /** 39 | * @param string $name 40 | */ 41 | public function setName($name) 42 | { 43 | $this->name = $name; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Claim/PublicClaim.php: -------------------------------------------------------------------------------- 1 | setName($name); 30 | } 31 | 32 | /** 33 | * @return string 34 | */ 35 | public function getName() 36 | { 37 | return $this->name; 38 | } 39 | 40 | /** 41 | * @param string $name 42 | */ 43 | public function setName($name) 44 | { 45 | $this->name = $name; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Claim/Subject.php: -------------------------------------------------------------------------------- 1 | '-', 22 | '/' => '_' 23 | ]; 24 | 25 | /** 26 | * @param boolean $urlSafe 27 | * @param boolean $strict 28 | */ 29 | public function __construct($urlSafe = true, $strict = true) 30 | { 31 | $this->urlSafe = (boolean)$urlSafe; 32 | $this->strict = (boolean)$strict; 33 | } 34 | 35 | /** 36 | * Return a URL-safe representation of a base64-encoded value. 37 | * 38 | * @param string $value 39 | * @return string 40 | */ 41 | protected function urlEncode($value) 42 | { 43 | return strtr(rtrim($value, '='), self::$urlSafeReplacements); 44 | } 45 | 46 | /** 47 | * @param string $value 48 | * @return string 49 | */ 50 | protected function urlDecode($value) 51 | { 52 | $urlUnsafeReplacements = array_flip(self::$urlSafeReplacements); 53 | 54 | $value = strtr($value, $urlUnsafeReplacements); 55 | 56 | switch (strlen($value) % 4) { 57 | case 0: 58 | // No pad chars in this case 59 | break; 60 | case 2: 61 | $value .= '=='; 62 | break; 63 | case 3: 64 | $value .= '='; 65 | break; 66 | case 1: 67 | default: 68 | throw new \RuntimeException('Value could not be decoded from URL safe representation.'); 69 | } 70 | 71 | return $value; 72 | } 73 | 74 | /** 75 | * @param string $value 76 | * @return string 77 | */ 78 | public function encode($value) 79 | { 80 | if (empty($value)) { 81 | return ''; 82 | } 83 | 84 | $encoded = base64_encode($value); 85 | 86 | if ($this->urlSafe) { 87 | $encoded = $this->urlEncode($encoded); 88 | } 89 | 90 | return $encoded; 91 | } 92 | 93 | /** 94 | * @param string $value 95 | * @return string 96 | */ 97 | public function decode($value) 98 | { 99 | if (empty($value)) { 100 | return $value; 101 | } 102 | 103 | if ($this->urlSafe) { 104 | $decoded = $this->urlDecode($value); 105 | } else { 106 | $decoded = $value; 107 | } 108 | 109 | $decoded = base64_decode($decoded, $this->strict); 110 | 111 | return $decoded; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Encoding/EncoderInterface.php: -------------------------------------------------------------------------------- 1 | algorithm = $algorithm; 20 | } 21 | 22 | /** 23 | * @return string 24 | */ 25 | public function getAlgorithmName() 26 | { 27 | return $this->algorithm->getName(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Encryption/Asymmetric.php: -------------------------------------------------------------------------------- 1 | privateKey) { 36 | throw new \RuntimeException('No private key available for encryption.'); 37 | } 38 | 39 | return $this->privateKey; 40 | } 41 | 42 | /** 43 | * @param resource|string $privateKey 44 | * @return $this 45 | */ 46 | public function setPrivateKey($privateKey) 47 | { 48 | $this->privateKey = $privateKey; 49 | return $this; 50 | } 51 | 52 | /** 53 | * @return resource|string 54 | */ 55 | public function getPublicKey() 56 | { 57 | if (!$this->publicKey) { 58 | throw new \RuntimeException('No public key available for verification.'); 59 | } 60 | 61 | return $this->publicKey; 62 | } 63 | 64 | /** 65 | * @param resource|string $publicKey 66 | * @return $this 67 | */ 68 | public function setPublicKey($publicKey) 69 | { 70 | $this->publicKey = $publicKey; 71 | return $this; 72 | } 73 | 74 | /** 75 | * @param string $value 76 | * @return string 77 | */ 78 | public function encrypt($value) 79 | { 80 | return $this->algorithm->sign($value, $this->getPrivateKey()); 81 | } 82 | 83 | /** 84 | * @param string $value 85 | * @param string $signature 86 | * @return boolean 87 | */ 88 | public function verify($value, $signature) 89 | { 90 | return $this->algorithm->verify($value, $signature, $this->getPublicKey()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Encryption/EncryptionInterface.php: -------------------------------------------------------------------------------- 1 | secret; 31 | } 32 | 33 | /** 34 | * @param string $secret 35 | * @return $this 36 | */ 37 | public function setSecret($secret) 38 | { 39 | $this->secret = $secret; 40 | return $this; 41 | } 42 | 43 | /** 44 | * @param string $value 45 | * @return string 46 | */ 47 | public function encrypt($value) 48 | { 49 | return $this->algorithm->compute($value); 50 | } 51 | 52 | /** 53 | * @param string $value 54 | * @param string $signature 55 | * @return boolean 56 | */ 57 | public function verify($value, $signature) 58 | { 59 | $computedValue = $this->algorithm->compute($value); 60 | 61 | return $this->timingSafeEquals($signature, $computedValue); 62 | } 63 | 64 | /** 65 | * A timing safe equals comparison. 66 | * 67 | * @see http://blog.ircmaxell.com/2014/11/its-all-about-time.html 68 | * 69 | * @param string $safe The internal (safe) value to be checked 70 | * @param string $user The user submitted (unsafe) value 71 | * 72 | * @return boolean True if the two strings are identical. 73 | */ 74 | public function timingSafeEquals($safe, $user) 75 | { 76 | if (function_exists('hash_equals')) { 77 | return hash_equals($user, $safe); 78 | } 79 | 80 | $safeLen = strlen($safe); 81 | $userLen = strlen($user); 82 | 83 | /* 84 | * In general, it's not possible to prevent length leaks. So it's OK to leak the length. 85 | * @see http://security.stackexchange.com/questions/49849/timing-safe-string-comparison-avoiding-length-leak 86 | */ 87 | if ($userLen != $safeLen) { 88 | return false; 89 | } 90 | 91 | $result = 0; 92 | 93 | for ($i = 0; $i < $userLen; $i++) { 94 | $result |= (ord($safe[$i]) ^ ord($user[$i])); 95 | } 96 | 97 | return $result === 0; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Exception/ExpiredException.php: -------------------------------------------------------------------------------- 1 | expiredAt = $expiredAt; 14 | $message = sprintf('Token expired at "%s"', $expiredAt->format('r')); 15 | parent::__construct($message, $code, $previous); 16 | } 17 | 18 | /** 19 | * @return \DateTime 20 | */ 21 | public function getExpiredAt() 22 | { 23 | return $this->expiredAt; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Exception/InvalidAudienceException.php: -------------------------------------------------------------------------------- 1 | validFrom = $validFrom; 14 | $message = sprintf('Token must not be processed before "%s"', $validFrom->format('r')); 15 | parent::__construct($message, $code, $previous); 16 | } 17 | 18 | /** 19 | * @return \DateTime 20 | */ 21 | public function getValidFrom() 22 | { 23 | return $this->validFrom; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Exception/VerificationException.php: -------------------------------------------------------------------------------- 1 | getClassMap(); 24 | $defaultClass = $this->getDefaultClass(); 25 | 26 | if (isset($classMap[$name])) { 27 | $class = $classMap[$name]; 28 | $parameter = new $class(); 29 | } else { 30 | $class = $defaultClass; 31 | $parameter = new $class($name); 32 | } 33 | 34 | return $parameter; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/HeaderParameter/AbstractParameter.php: -------------------------------------------------------------------------------- 1 | setValue($value); 18 | } 19 | 20 | /** 21 | * @return mixed 22 | */ 23 | public function getValue() 24 | { 25 | return $this->value; 26 | } 27 | 28 | /** 29 | * @param mixed 30 | */ 31 | public function setValue($value) 32 | { 33 | $this->value = $value; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/HeaderParameter/Algorithm.php: -------------------------------------------------------------------------------- 1 | getValue(); 59 | 60 | if (!in_array($parameter->getName(), $value)) { 61 | $value[] = $parameter->getName(); 62 | $this->setValue($value); 63 | } 64 | } 65 | 66 | /** 67 | * @return string 68 | */ 69 | public function getName() 70 | { 71 | return self::NAME; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/HeaderParameter/Custom.php: -------------------------------------------------------------------------------- 1 | setName($name); 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public function getName() 27 | { 28 | return $this->name; 29 | } 30 | 31 | /** 32 | * @param string $name 33 | */ 34 | public function setName($name) 35 | { 36 | $this->name = $name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/HeaderParameter/Factory.php: -------------------------------------------------------------------------------- 1 | 'Emarref\Jwt\HeaderParameter\Algorithm', 24 | ContentType::NAME => 'Emarref\Jwt\HeaderParameter\ContentType', 25 | Critical::NAME => 'Emarref\Jwt\HeaderParameter\Critical', 26 | JsonWebKey::NAME => 'Emarref\Jwt\HeaderParameter\JsonWebKey', 27 | JwkSetUrl::NAME => 'Emarref\Jwt\HeaderParameter\JwkSetUrl', 28 | KeyId::NAME => 'Emarref\Jwt\HeaderParameter\KeyId', 29 | Type::NAME => 'Emarref\Jwt\HeaderParameter\Type', 30 | X509CertificateChain::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateChain', 31 | X509CertificateSha1Thumbprint::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateSha1Thumbprint', 32 | X509CertificateSha256Thumbprint::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateSha256Thumbprint', 33 | X509Url::NAME => 'Emarref\Jwt\HeaderParameter\X509Url', 34 | ]; 35 | 36 | /** 37 | * @return array 38 | */ 39 | protected function getClassMap() 40 | { 41 | return self::$classMap; 42 | } 43 | 44 | /** 45 | * @return string 46 | */ 47 | protected function getDefaultClass() 48 | { 49 | return self::$customParameterClass; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/HeaderParameter/JsonWebKey.php: -------------------------------------------------------------------------------- 1 | encoder = new Encoding\Base64(); 25 | } 26 | 27 | /** 28 | * @param string $jwt 29 | * @return Token 30 | */ 31 | public function deserialize($jwt) 32 | { 33 | $serialization = new Serialization\Compact( 34 | $this->encoder, 35 | new HeaderParameter\Factory(), 36 | new Claim\Factory() 37 | ); 38 | 39 | return $serialization->deserialize($jwt); 40 | } 41 | 42 | /** 43 | * @param Token $token 44 | * @param Encryption\EncryptionInterface $encryption 45 | * @return string 46 | */ 47 | public function serialize(Token $token, Encryption\EncryptionInterface $encryption) 48 | { 49 | $this->sign($token, $encryption); 50 | 51 | $serialization = new Serialization\Compact( 52 | $this->encoder, 53 | new HeaderParameter\Factory(), 54 | new Claim\Factory() 55 | ); 56 | 57 | return $serialization->serialize($token); 58 | } 59 | 60 | /** 61 | * @param Token $token 62 | * @param Encryption\EncryptionInterface $encryption 63 | */ 64 | public function sign(Token $token, Encryption\EncryptionInterface $encryption) 65 | { 66 | $signer = new Signature\Jws($encryption, $this->encoder); 67 | 68 | $signer->sign($token); 69 | } 70 | 71 | /** 72 | * @param Verification\Context $context 73 | * @return Verification\VerifierInterface[] 74 | */ 75 | protected function getVerifiers(Verification\Context $context) 76 | { 77 | return [ 78 | new Verification\EncryptionVerifier($context->getEncryption(), $this->encoder), 79 | new Verification\AudienceVerifier($context->getAudience()), 80 | new Verification\ExpirationVerifier(), 81 | new Verification\IssuerVerifier($context->getIssuer()), 82 | new Verification\SubjectVerifier($context->getSubject()), 83 | new Verification\NotBeforeVerifier(), 84 | ]; 85 | } 86 | 87 | /** 88 | * @param Token $token 89 | * @param Verification\Context $context 90 | * @return bool 91 | */ 92 | public function verify(Token $token, Verification\Context $context) 93 | { 94 | foreach ($this->getVerifiers($context) as $verifier) { 95 | $verifier->verify($token); 96 | } 97 | 98 | return true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Serialization/Compact.php: -------------------------------------------------------------------------------- 1 | encoding = $encoding; 38 | $this->headerParameterFactory = $headerParameterFactory; 39 | $this->claimFactory = $claimFactory; 40 | } 41 | 42 | /** 43 | * @param string $headersJson 44 | * 45 | * @return HeaderParameter\ParameterInterface[] 46 | * @throws \InvalidArgumentException 47 | */ 48 | protected function parseHeaders($headersJson) 49 | { 50 | $parameters = []; 51 | $headers = json_decode($headersJson, true); 52 | 53 | if (!is_array($headers) || empty($headers)) { 54 | throw new \InvalidArgumentException('Not a valid header of JWT string passed for deserialization'); 55 | } 56 | 57 | foreach ($headers as $name => $value) { 58 | $parameter = $this->headerParameterFactory->get($name); 59 | $parameter->setValue($value); 60 | $parameters[] = $parameter; 61 | } 62 | 63 | return $parameters; 64 | } 65 | 66 | /** 67 | * @param string $payloadJson 68 | * 69 | * @return Claim\ClaimInterface[] 70 | * @throws \InvalidArgumentException 71 | */ 72 | protected function parsePayload($payloadJson) 73 | { 74 | $claims = []; 75 | $payload = json_decode($payloadJson, true); 76 | 77 | if (!is_array($payload)) { 78 | throw new \InvalidArgumentException('Not a valid payload of JWT string passed for deserialization'); 79 | } 80 | 81 | foreach ($payload as $name => $value) { 82 | $claim = $this->claimFactory->get($name); 83 | $claim->setValue($value); 84 | $claims[] = $claim; 85 | } 86 | 87 | return $claims; 88 | } 89 | 90 | /** 91 | * @param string $jwt 92 | * 93 | * @return Token 94 | * @throws \InvalidArgumentException 95 | */ 96 | public function deserialize($jwt) 97 | { 98 | $token = new Token(); 99 | 100 | if (empty($jwt)) { 101 | throw new \InvalidArgumentException('Not a valid JWT string passed for deserialization'); 102 | } 103 | 104 | list($encodedHeader, $encodedPayload, $encodedSignature) = array_pad(explode('.', $jwt, 3), 3, null); 105 | 106 | $decodedHeader = $this->encoding->decode($encodedHeader); 107 | $decodedPayload = $this->encoding->decode($encodedPayload); 108 | $decodedSignature = $this->encoding->decode($encodedSignature); 109 | 110 | foreach ($this->parseHeaders($decodedHeader) as $header) { 111 | $token->addHeader($header); 112 | } 113 | 114 | foreach ($this->parsePayload($decodedPayload) as $claim) { 115 | $token->addClaim($claim); 116 | } 117 | 118 | $token->setSignature($decodedSignature); 119 | 120 | return $token; 121 | } 122 | 123 | /** 124 | * @param Token $token 125 | * @return string 126 | */ 127 | public function serialize(Token $token) 128 | { 129 | $serializedHeader = $token->getHeader()->getParameters()->jsonSerialize(); 130 | $serializedPayload = $token->getPayload()->getClaims()->jsonSerialize(); 131 | $signature = $token->getSignature(); 132 | 133 | return sprintf('%s.%s.%s', 134 | $this->encoding->encode($serializedHeader), 135 | $this->encoding->encode($serializedPayload), 136 | $this->encoding->encode($signature) 137 | ); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Serialization/SerializerInterface.php: -------------------------------------------------------------------------------- 1 | encryption = $encryption; 25 | $this->encoder = $encoder; 26 | } 27 | 28 | public function getUnsignedValue(Token $token) 29 | { 30 | $jsonHeader = $token->getHeader()->getParameters()->jsonSerialize(); 31 | $encodedHeader = $this->encoder->encode($jsonHeader); 32 | 33 | $jsonPayload = $token->getPayload()->getClaims()->jsonSerialize(); 34 | $encodedPayload = $this->encoder->encode($jsonPayload); 35 | 36 | return sprintf('%s.%s', $encodedHeader, $encodedPayload); 37 | } 38 | 39 | public function sign(Token $token) 40 | { 41 | $token->addHeader(new Algorithm($this->encryption->getAlgorithmName())); 42 | 43 | $rawSignature = $this->getUnsignedValue($token); 44 | 45 | $signature = $this->encryption->encrypt($rawSignature); 46 | 47 | $token->setSignature($signature); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Signature/README.md: -------------------------------------------------------------------------------- 1 | # JSON Web Signature (JWS) 2 | 3 | See the [JSON Web Signature (JWS)](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-36) spec for more 4 | information regarding signatures in JWT. 5 | -------------------------------------------------------------------------------- /src/Signature/SignerInterface.php: -------------------------------------------------------------------------------- 1 | header = new Header(); 30 | $this->payload = new Payload(); 31 | } 32 | 33 | /** 34 | * @param HeaderParameter\ParameterInterface $parameter 35 | * @param bool $critical 36 | */ 37 | public function addHeader(HeaderParameter\ParameterInterface $parameter, $critical = false) 38 | { 39 | $this->header->setParameter($parameter, $critical); 40 | } 41 | 42 | /** 43 | * @param Claim\ClaimInterface $claim 44 | */ 45 | public function addClaim(Claim\ClaimInterface $claim) 46 | { 47 | $this->payload->setClaim($claim); 48 | } 49 | 50 | /** 51 | * @return Token\Header 52 | */ 53 | public function getHeader() 54 | { 55 | return $this->header; 56 | } 57 | 58 | /** 59 | * @return Token\Payload 60 | */ 61 | public function getPayload() 62 | { 63 | return $this->payload; 64 | } 65 | 66 | /** 67 | * @return string 68 | */ 69 | public function getSignature() 70 | { 71 | return $this->signature; 72 | } 73 | 74 | /** 75 | * @param string $signature 76 | */ 77 | public function setSignature($signature) 78 | { 79 | $this->signature = $signature; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Token/Header.php: -------------------------------------------------------------------------------- 1 | propertyList = new PropertyList(); 18 | } 19 | 20 | /** 21 | * @param HeaderParameter\ParameterInterface $parameter 22 | * @param boolean $critical 23 | */ 24 | public function setParameter(HeaderParameter\ParameterInterface $parameter, $critical = false) 25 | { 26 | $this->propertyList->setProperty($parameter); 27 | 28 | if ($critical) { 29 | /** @var HeaderParameter\Critical $criticalParameter */ 30 | $criticalParameter = $this->findParameterByName(HeaderParameter\Critical::NAME); 31 | 32 | if (!$criticalParameter) { 33 | $criticalParameter = new HeaderParameter\Critical(); 34 | } 35 | 36 | $criticalParameter->addParameter($parameter); 37 | $this->propertyList->setProperty($criticalParameter); 38 | } 39 | } 40 | 41 | /** 42 | * @param string $name 43 | * @return HeaderParameter\ParameterInterface|null 44 | */ 45 | public function findParameterByName($name) 46 | { 47 | foreach ($this->propertyList as $parameter) { 48 | /** @var HeaderParameter\ParameterInterface $parameter */ 49 | if ($parameter->getName() === $name) { 50 | return $parameter; 51 | } 52 | } 53 | 54 | return null; 55 | } 56 | 57 | /** 58 | * @return PropertyList 59 | */ 60 | public function getParameters() 61 | { 62 | return $this->propertyList; 63 | } 64 | 65 | /** 66 | * @return string 67 | */ 68 | public function jsonSerialize() 69 | { 70 | return $this->propertyList->jsonSerialize(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Token/Payload.php: -------------------------------------------------------------------------------- 1 | propertyList = new PropertyList(); 17 | } 18 | 19 | /** 20 | * @param Claim\ClaimInterface $claim 21 | */ 22 | public function setClaim(Claim\ClaimInterface $claim) 23 | { 24 | $this->propertyList->setProperty($claim); 25 | } 26 | 27 | /** 28 | * @param string $name 29 | * @return Claim\ClaimInterface|null 30 | */ 31 | public function findClaimByName($name) 32 | { 33 | foreach ($this->propertyList as $claim) { 34 | /** @var Claim\ClaimInterface $claim */ 35 | if ($claim->getName() === $name) { 36 | return $claim; 37 | } 38 | } 39 | 40 | return null; 41 | } 42 | 43 | /** 44 | * @return PropertyList 45 | */ 46 | public function getClaims() 47 | { 48 | return $this->propertyList; 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function jsonSerialize() 55 | { 56 | return $this->propertyList->jsonSerialize(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Token/PropertyInterface.php: -------------------------------------------------------------------------------- 1 | properties = new \ArrayObject(); 15 | } 16 | 17 | /** 18 | * @param PropertyInterface $property 19 | */ 20 | public function setProperty(PropertyInterface $property) 21 | { 22 | $this->properties[$property->getName()] = $property; 23 | } 24 | 25 | /** 26 | * @return string 27 | */ 28 | public function jsonSerialize() 29 | { 30 | $properties = new \stdClass(); 31 | 32 | foreach ($this->properties as $property) { 33 | $name = $property->getName(); 34 | $value = $property->getValue(); 35 | 36 | if (empty($name) || empty($value)) { 37 | continue; 38 | } 39 | 40 | $properties->$name = $value; 41 | } 42 | 43 | return json_encode($properties); 44 | } 45 | 46 | /** 47 | * @return PropertyInterface[] 48 | */ 49 | public function getIterator() 50 | { 51 | return $this->properties; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Verification/AudienceVerifier.php: -------------------------------------------------------------------------------- 1 | audience = $audience; 26 | } 27 | 28 | /** 29 | * @param Token $token 30 | * @throws InvalidAudienceException 31 | */ 32 | public function verify(Token $token) 33 | { 34 | /** @var Claim\Audience $audienceClaim */ 35 | $audienceClaim = $token->getPayload()->findClaimByName(Claim\Audience::NAME); 36 | 37 | $audience = (null === $audienceClaim) ? null : $audienceClaim->getValue(); 38 | 39 | if (!is_array($audience)) { 40 | $audience = [$audience]; 41 | } 42 | 43 | if (!in_array($this->audience, $audience, true)) { 44 | throw new InvalidAudienceException; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Verification/Context.php: -------------------------------------------------------------------------------- 1 | setEncryption($encryption); 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function getAudience() 41 | { 42 | return $this->audience; 43 | } 44 | 45 | /** 46 | * @param string $audience 47 | * @return $this 48 | */ 49 | public function setAudience($audience) 50 | { 51 | $this->audience = $audience; 52 | return $this; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function getIssuer() 59 | { 60 | return $this->issuer; 61 | } 62 | 63 | /** 64 | * @param string $issuer 65 | * @return $this 66 | */ 67 | public function setIssuer($issuer) 68 | { 69 | $this->issuer = $issuer; 70 | return $this; 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | public function getSubject() 77 | { 78 | return $this->subject; 79 | } 80 | 81 | /** 82 | * @param string $subject 83 | * @return $this 84 | */ 85 | public function setSubject($subject) 86 | { 87 | $this->subject = $subject; 88 | return $this; 89 | } 90 | 91 | /** 92 | * @return EncryptionInterface 93 | */ 94 | public function getEncryption() 95 | { 96 | return $this->encryption; 97 | } 98 | 99 | /** 100 | * @param EncryptionInterface $encryption 101 | * @return $this 102 | */ 103 | public function setEncryption($encryption) 104 | { 105 | $this->encryption = $encryption; 106 | return $this; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Verification/EncryptionVerifier.php: -------------------------------------------------------------------------------- 1 | encryption = $encryption; 36 | $this->encoder = $encoder; 37 | $this->signer = new Signature\Jws($this->encryption, $this->encoder); 38 | } 39 | 40 | /** 41 | * @param Token $token 42 | * @throws InvalidSignatureException 43 | */ 44 | public function verify(Token $token) 45 | { 46 | /** @var HeaderParameter\Algorithm $algorithmParameter */ 47 | $algorithmParameter = $token->getHeader()->findParameterByName(HeaderParameter\Algorithm::NAME); 48 | 49 | if (null === $algorithmParameter) { 50 | throw new \RuntimeException('Algorithm parameter not found in token header.'); 51 | } 52 | 53 | if ($algorithmParameter->getValue() !== $this->encryption->getAlgorithmName()) { 54 | throw new \RuntimeException(sprintf( 55 | 'Cannot use "%s" algorithm to decrypt token encrypted with algorithm "%s".', 56 | $this->encryption->getAlgorithmName(), 57 | $algorithmParameter->getValue() 58 | )); 59 | } 60 | 61 | if (!$this->encryption->verify($this->signer->getUnsignedValue($token), $token->getSignature())) { 62 | throw new InvalidSignatureException; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Verification/ExpirationVerifier.php: -------------------------------------------------------------------------------- 1 | getValue())) { 19 | throw new \InvalidArgumentException(sprintf( 20 | 'Invalid expiration timestamp "%s"', 21 | $expirationClaim->getValue() 22 | )); 23 | } 24 | 25 | $expiration = new \DateTime(); 26 | $expiration->setTimestamp($expirationClaim->getValue()); 27 | return $expiration; 28 | } 29 | 30 | public function verify(Token $token) 31 | { 32 | /** @var Claim\Expiration $expirationClaim */ 33 | $expirationClaim = $token->getPayload()->findClaimByName(Claim\Expiration::NAME); 34 | 35 | if (null === $expirationClaim) { 36 | return null; 37 | } 38 | 39 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 40 | 41 | if ($now->getTimestamp() > $expirationClaim->getValue()) { 42 | $expiration = $this->getDateTimeFromClaim($expirationClaim); 43 | throw new ExpiredException($expiration); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Verification/IssuerVerifier.php: -------------------------------------------------------------------------------- 1 | issuer = $issuer; 26 | } 27 | 28 | /** 29 | * @param Token $token 30 | * @throws InvalidIssuerException 31 | */ 32 | public function verify(Token $token) 33 | { 34 | /** @var Claim\Issuer $issuerClaim */ 35 | $issuerClaim = $token->getPayload()->findClaimByName(Claim\Issuer::NAME); 36 | 37 | $issuer = (null === $issuerClaim) ? null : $issuerClaim->getValue(); 38 | 39 | if ($this->issuer !== $issuer) { 40 | throw new InvalidIssuerException; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Verification/NotBeforeVerifier.php: -------------------------------------------------------------------------------- 1 | getPayload()->findClaimByName(Claim\NotBefore::NAME); 15 | 16 | if (null === $notBeforeClaim) { 17 | return null; 18 | } 19 | 20 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 21 | 22 | if (!is_long($notBeforeClaim->getValue())) { 23 | throw new \InvalidArgumentException(sprintf( 24 | 'Invalid not before timestamp "%s"', 25 | $notBeforeClaim->getValue() 26 | )); 27 | } 28 | 29 | if ($now->getTimestamp() < $notBeforeClaim->getValue()) { 30 | $notBefore = new \DateTime(); 31 | $notBefore->setTimestamp($notBeforeClaim->getValue()); 32 | throw new TooEarlyException($notBefore); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Verification/SubjectVerifier.php: -------------------------------------------------------------------------------- 1 | subject = $subject; 26 | } 27 | 28 | /** 29 | * @param Token $token 30 | * @throws InvalidSubjectException 31 | */ 32 | public function verify(Token $token) 33 | { 34 | /** @var Claim\Subject $subjectClaim */ 35 | $subjectClaim = $token->getPayload()->findClaimByName(Claim\Subject::NAME); 36 | 37 | $subject = (null === $subjectClaim) ? null : $subjectClaim->getValue(); 38 | 39 | if ($this->subject !== $subject) { 40 | throw new InvalidSubjectException; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Verification/VerifierInterface.php: -------------------------------------------------------------------------------- 1 | algorithm = new Hs256(self::$secret); 20 | } 21 | 22 | public function testGetName() 23 | { 24 | $this->assertSame(self::$name, $this->algorithm->getName()); 25 | } 26 | 27 | public function testCompute() 28 | { 29 | $unencryptedValue = 'foobar'; 30 | $encryptedValue = hash_hmac(self::ALGORITHM, $unencryptedValue, self::$secret, true); 31 | $this->assertSame($encryptedValue, $this->algorithm->compute($unencryptedValue)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/Algorithm/Hs384Test.php: -------------------------------------------------------------------------------- 1 | algorithm = new Hs384(self::$secret); 20 | } 21 | 22 | public function testGetName() 23 | { 24 | $this->assertSame(self::$name, $this->algorithm->getName()); 25 | } 26 | 27 | public function testCompute() 28 | { 29 | $unencryptedValue = 'foobar'; 30 | $encryptedValue = hash_hmac(self::ALGORITHM, $unencryptedValue, self::$secret, true); 31 | $this->assertSame($encryptedValue, $this->algorithm->compute($unencryptedValue)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/Algorithm/Hs512Test.php: -------------------------------------------------------------------------------- 1 | algorithm = new Hs512(self::$secret); 20 | } 21 | 22 | public function testGetName() 23 | { 24 | $this->assertSame(self::$name, $this->algorithm->getName()); 25 | } 26 | 27 | public function testCompute() 28 | { 29 | $unencryptedValue = 'foobar'; 30 | $encryptedValue = hash_hmac(self::ALGORITHM, $unencryptedValue, self::$secret, true); 31 | $this->assertSame($encryptedValue, $this->algorithm->compute($unencryptedValue)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/Algorithm/Ps256Test.php: -------------------------------------------------------------------------------- 1 | key = openssl_pkey_new(); 23 | $this->algorithm = new Rs256(); 24 | } 25 | 26 | public function testGetName() 27 | { 28 | $this->assertSame(self::$name, $this->algorithm->getName()); 29 | } 30 | 31 | public function testGetAlgorithm() 32 | { 33 | $this->assertSame(self::$algorithmName, $this->algorithm->getAlgorithm()); 34 | } 35 | 36 | public function testSign() 37 | { 38 | $unencryptedValue = 'foobar'; 39 | openssl_sign($unencryptedValue, $encryptedValue, $this->key, OPENSSL_ALGO_SHA256); 40 | $signature = $this->algorithm->sign($unencryptedValue, $this->key); 41 | 42 | $this->assertSame($encryptedValue, $signature); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/Algorithm/Rs384Test.php: -------------------------------------------------------------------------------- 1 | key = openssl_pkey_new(); 23 | $this->algorithm = new Rs384(); 24 | } 25 | 26 | public function testGetName() 27 | { 28 | $this->assertSame(self::$name, $this->algorithm->getName()); 29 | } 30 | 31 | public function testGetAlgorithm() 32 | { 33 | $this->assertSame(self::$algorithmName, $this->algorithm->getAlgorithm()); 34 | } 35 | 36 | public function testSign() 37 | { 38 | $unencryptedValue = 'foobar'; 39 | openssl_sign($unencryptedValue, $encryptedValue, $this->key, OPENSSL_ALGO_SHA384); 40 | $signature = $this->algorithm->sign($unencryptedValue, $this->key); 41 | 42 | $this->assertSame($encryptedValue, $signature); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/Algorithm/Rs512Test.php: -------------------------------------------------------------------------------- 1 | key = openssl_pkey_new(); 23 | $this->algorithm = new Rs512(); 24 | } 25 | 26 | public function testGetName() 27 | { 28 | $this->assertSame(self::$name, $this->algorithm->getName()); 29 | } 30 | 31 | public function testGetAlgorithm() 32 | { 33 | $this->assertSame(self::$algorithmName, $this->algorithm->getAlgorithm()); 34 | } 35 | 36 | public function testCompute() 37 | { 38 | $unencryptedValue = 'foobar'; 39 | openssl_sign($unencryptedValue, $encryptedValue, $this->key, OPENSSL_ALGO_SHA512); 40 | $signature = $this->algorithm->sign($unencryptedValue, $this->key); 41 | 42 | $this->assertSame($encryptedValue, $signature); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/Claim/AudienceTest.php: -------------------------------------------------------------------------------- 1 | claim = new Audience(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testStringValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->claim->setValue($newValue); 35 | $this->assertSame($newValue, $this->claim->getValue()); 36 | } 37 | 38 | public function testArrayValue() 39 | { 40 | $this->claim->setValue([self::$value]); 41 | $this->assertSame([self::$value], $this->claim->getValue()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/Claim/ExpirationTest.php: -------------------------------------------------------------------------------- 1 | claim = new Expiration(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testTimestampValue() 31 | { 32 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 33 | 34 | $this->claim->setValue($now->getTimestamp()); 35 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 36 | } 37 | 38 | public function testDateTimeValue() 39 | { 40 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 41 | 42 | $this->claim->setValue($now); 43 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 44 | } 45 | 46 | public function testTimezone() 47 | { 48 | $akl = new \DateTime('2014-01-01 13:00:00', new \DateTimeZone('Pacific/Auckland')); 49 | $utc = new \DateTime('2014-01-01 00:00:00', new \DateTimeZone('UTC')); 50 | 51 | $this->claim->setValue($akl); 52 | $this->assertSame($utc->getTimestamp(), $this->claim->getValue()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/Claim/FactoryTest.php: -------------------------------------------------------------------------------- 1 | 'Emarref\Jwt\Claim\Audience', 9 | Expiration::NAME => 'Emarref\Jwt\Claim\Expiration', 10 | IssuedAt::NAME => 'Emarref\Jwt\Claim\IssuedAt', 11 | Issuer::NAME => 'Emarref\Jwt\Claim\Issuer', 12 | JwtId::NAME => 'Emarref\Jwt\Claim\JwtId', 13 | NotBefore::NAME => 'Emarref\Jwt\Claim\NotBefore', 14 | Subject::NAME => 'Emarref\Jwt\Claim\Subject', 15 | 'private' => 'Emarref\Jwt\Claim\PrivateClaim', 16 | ]; 17 | 18 | /** 19 | * @var Factory 20 | */ 21 | private $factory; 22 | 23 | public function setUp() 24 | { 25 | $this->factory = new Factory(); 26 | } 27 | 28 | public function testGetAudience() 29 | { 30 | $this->assertInstanceOf(self::$classMap[Audience::NAME], $this->factory->get(Audience::NAME)); 31 | } 32 | 33 | public function testGetExpiration() 34 | { 35 | $this->assertInstanceOf(self::$classMap[Expiration::NAME], $this->factory->get(Expiration::NAME)); 36 | } 37 | 38 | public function testGetIssuedAt() 39 | { 40 | $this->assertInstanceOf(self::$classMap[IssuedAt::NAME], $this->factory->get(IssuedAt::NAME)); 41 | } 42 | 43 | public function testGetIssuer() 44 | { 45 | $this->assertInstanceOf(self::$classMap[Issuer::NAME], $this->factory->get(Issuer::NAME)); 46 | } 47 | 48 | public function testGetJwtId() 49 | { 50 | $this->assertInstanceOf(self::$classMap[JwtId::NAME], $this->factory->get(JwtId::NAME)); 51 | } 52 | 53 | public function testGetNotBefore() 54 | { 55 | $this->assertInstanceOf(self::$classMap[NotBefore::NAME], $this->factory->get(NotBefore::NAME)); 56 | } 57 | 58 | public function testGetSubject() 59 | { 60 | $this->assertInstanceOf(self::$classMap[Subject::NAME], $this->factory->get(Subject::NAME)); 61 | } 62 | 63 | public function testGetPrivate() 64 | { 65 | $this->assertInstanceOf(self::$classMap['private'], $this->factory->get('unknown')); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/Claim/IssuedAtTest.php: -------------------------------------------------------------------------------- 1 | claim = new IssuedAt(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testTimestampValue() 31 | { 32 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 33 | 34 | $this->claim->setValue($now->getTimestamp()); 35 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 36 | } 37 | 38 | public function testDateTimeValue() 39 | { 40 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 41 | 42 | $this->claim->setValue($now); 43 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 44 | } 45 | 46 | public function testTimezone() 47 | { 48 | $akl = new \DateTime('2014-01-01 13:00:00', new \DateTimeZone('Pacific/Auckland')); 49 | $utc = new \DateTime('2014-01-01 00:00:00', new \DateTimeZone('UTC')); 50 | 51 | $this->claim->setValue($akl); 52 | $this->assertSame($utc->getTimestamp(), $this->claim->getValue()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/Claim/IssuerTest.php: -------------------------------------------------------------------------------- 1 | claim = new Issuer(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->claim->setValue($newValue); 35 | $this->assertSame($newValue, $this->claim->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Claim/JwtIdTest.php: -------------------------------------------------------------------------------- 1 | claim = new JwtId(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->claim->setValue($newValue); 35 | $this->assertSame($newValue, $this->claim->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Claim/NotBeforeTest.php: -------------------------------------------------------------------------------- 1 | claim = new NotBefore(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testTimestampValue() 31 | { 32 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 33 | 34 | $this->claim->setValue($now->getTimestamp()); 35 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 36 | } 37 | 38 | public function testDateTimeValue() 39 | { 40 | $now = new \DateTime('now', new \DateTimeZone('UTC')); 41 | 42 | $this->claim->setValue($now); 43 | $this->assertSame($now->getTimestamp(), $this->claim->getValue()); 44 | } 45 | 46 | public function testTimezone() 47 | { 48 | $akl = new \DateTime('2014-01-01 13:00:00', new \DateTimeZone('Pacific/Auckland')); 49 | $utc = new \DateTime('2014-01-01 00:00:00', new \DateTimeZone('UTC')); 50 | 51 | $this->claim->setValue($akl); 52 | $this->assertSame($utc->getTimestamp(), $this->claim->getValue()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/Claim/PrivateClaimTest.php: -------------------------------------------------------------------------------- 1 | claim = new PrivateClaim(self::$name, self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testSetName() 26 | { 27 | $newName = 'baz'; 28 | 29 | $this->claim->setName($newName); 30 | 31 | $this->assertSame($newName, $this->claim->getName()); 32 | } 33 | 34 | public function testGetValue() 35 | { 36 | $this->assertSame(self::$value, $this->claim->getValue()); 37 | } 38 | 39 | public function testSetValue() 40 | { 41 | $newValue = 'NewValue'; 42 | 43 | $this->claim->setValue($newValue); 44 | 45 | $this->assertSame($newValue, $this->claim->getValue()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/Claim/PublicClaimTest.php: -------------------------------------------------------------------------------- 1 | claim = new PublicClaim(self::$name, self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testSetName() 26 | { 27 | $newName = 'foo://baz'; 28 | 29 | $this->claim->setName($newName); 30 | 31 | $this->assertSame($newName, $this->claim->getName()); 32 | } 33 | 34 | public function testGetValue() 35 | { 36 | $this->assertSame(self::$value, $this->claim->getValue()); 37 | } 38 | 39 | public function testSetValue() 40 | { 41 | $newValue = 'NewValue'; 42 | 43 | $this->claim->setValue($newValue); 44 | 45 | $this->assertSame($newValue, $this->claim->getValue()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/Claim/SubjectTest.php: -------------------------------------------------------------------------------- 1 | claim = new Subject(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->claim->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->claim->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->claim->setValue($newValue); 35 | $this->assertSame($newValue, $this->claim->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Encoding/Base64Test.php: -------------------------------------------------------------------------------- 1 | defaultEncoding = new Base64(); 22 | $this->nonDefaultEncoding = new Base64(false, false); 23 | } 24 | 25 | public function testEncode() 26 | { 27 | $this->assertSame('ZsO4w7hiYXJiYXo', $this->defaultEncoding->encode(self::$value)); 28 | $this->assertSame('ZsO4w7hiYXJiYXo=', $this->nonDefaultEncoding->encode(self::$value)); 29 | } 30 | 31 | public function testDecode() 32 | { 33 | $this->assertSame(self::$value, $this->defaultEncoding->decode('ZsO4w7hiYXJiYXo')); 34 | $this->assertSame(self::$value, $this->nonDefaultEncoding->decode('ZsO4w7hiYXJiYXo=')); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/Encryption/AsymmetricTest.php: -------------------------------------------------------------------------------- 1 | algorithm = $this->getMockBuilder('Emarref\Jwt\Algorithm\Rs256')->getMock(); 20 | 21 | $this->encryption = new Asymmetric($this->algorithm); 22 | } 23 | 24 | /** 25 | * @expectedException \RuntimeException 26 | */ 27 | public function testGetPrivateKeyUnavailable() 28 | { 29 | $this->encryption->getPrivateKey(); 30 | } 31 | 32 | public function testPrivateKey() 33 | { 34 | $key = 'thisismykey'; 35 | 36 | $this->encryption->setPrivateKey('thisismykey'); 37 | 38 | $this->assertSame($key, $this->encryption->getPrivateKey()); 39 | } 40 | 41 | /** 42 | * @expectedException \RuntimeException 43 | */ 44 | public function testGetPublicKeyUnavailable() 45 | { 46 | $this->encryption->getPublicKey(); 47 | } 48 | 49 | public function testPublicKey() 50 | { 51 | $key = 'thisismykey'; 52 | 53 | $this->encryption->setPublicKey('thisismykey'); 54 | 55 | $this->assertSame($key, $this->encryption->getPublicKey()); 56 | } 57 | 58 | /** 59 | * @expectedException \RuntimeException 60 | * @expectedExceptionMessage No private key available for encryption. 61 | */ 62 | public function testEncryptNoPrivateKey() 63 | { 64 | $this->algorithm->expects($this->never()) 65 | ->method('sign'); 66 | 67 | $this->encryption->encrypt('myvalue'); 68 | } 69 | 70 | public function testEncrypt() 71 | { 72 | $unencryptedValue = 'unencrypted_value'; 73 | $encryptedValue = 'encrypted_value'; 74 | $privateKey = 'private_key'; 75 | 76 | $this->encryption->setPrivateKey($privateKey); 77 | 78 | $this->algorithm->expects($this->once()) 79 | ->method('sign') 80 | ->with($unencryptedValue, $privateKey) 81 | ->will($this->returnValue($encryptedValue)); 82 | 83 | $this->assertSame($encryptedValue, $this->encryption->encrypt($unencryptedValue)); 84 | } 85 | 86 | /** 87 | * @expectedException \RuntimeException 88 | * @expectedExceptionMessage No public key available for verification. 89 | */ 90 | public function testVerifyNoPublicKey() 91 | { 92 | $this->algorithm->expects($this->never()) 93 | ->method('verify'); 94 | 95 | $this->encryption->verify('value', 'signature'); 96 | } 97 | 98 | public function testVerify() 99 | { 100 | $value = 'value'; 101 | $signature = 'signature'; 102 | $publicKey = 'public_key'; 103 | $encryptedValue = 'encrypted_value'; 104 | 105 | $this->encryption->setPublicKey($publicKey); 106 | 107 | $this->algorithm->expects($this->once()) 108 | ->method('verify') 109 | ->with($value, $signature, $publicKey) 110 | ->will($this->returnValue($encryptedValue)); 111 | 112 | $this->encryption->verify($value, $signature); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /test/Encryption/FactoryTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf($expectedEncryptionInstance, Factory::create($algorithm)); 16 | } 17 | 18 | public function testSymmetricCreation() 19 | { 20 | $expectedEncryptionInstance = 'Emarref\Jwt\Encryption\Symmetric'; 21 | 22 | $algorithm = new Algorithm\Hs256('secret'); 23 | 24 | $this->assertInstanceOf($expectedEncryptionInstance, Factory::create($algorithm)); 25 | } 26 | 27 | /** 28 | * @expectedException \InvalidArgumentException 29 | * @expectedExceptionMessage Algorithm of class "Emarref\Jwt\Encryption\UnknownAlgorithmStub" is neither symmetric or asymmetric. 30 | */ 31 | public function testUnknownEncryption() 32 | { 33 | $algorithm = new UnknownAlgorithmStub(); 34 | 35 | Factory::create($algorithm); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Encryption/SymmetricTest.php: -------------------------------------------------------------------------------- 1 | algorithm = $this->getMockBuilder('Emarref\Jwt\Algorithm\Hs256') 20 | ->setConstructorArgs(['secret']) 21 | ->getMock(); 22 | 23 | $this->encryption = new Symmetric($this->algorithm); 24 | } 25 | 26 | public function testEncrypt() 27 | { 28 | $value = 'value'; 29 | $computedValue = 'computed_value'; 30 | 31 | $this->algorithm->expects($this->once()) 32 | ->method('compute') 33 | ->with($value) 34 | ->will($this->returnValue($computedValue)); 35 | 36 | $this->assertSame($computedValue, $this->encryption->encrypt($value)); 37 | } 38 | 39 | public function testVerify() 40 | { 41 | $value = 'value'; 42 | $signature = 'signature'; 43 | 44 | $badValue = 'bad_value'; 45 | $badSignature = 'bad_signature'; 46 | 47 | $this->algorithm->expects($this->exactly(2)) 48 | ->method('compute') 49 | ->will($this->returnValueMap([ 50 | [$value, $signature], 51 | [$badValue, 'wontverify'], 52 | ])); 53 | 54 | $this->assertTrue($this->encryption->verify($value, $signature)); 55 | $this->assertFalse($this->encryption->verify($badValue, $badSignature)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/Encryption/UnknownAlgorithmStub.php: -------------------------------------------------------------------------------- 1 | parameter = new Algorithm(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/ContentTypeTest.php: -------------------------------------------------------------------------------- 1 | parameter = new ContentType(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/CriticalTest.php: -------------------------------------------------------------------------------- 1 | parameter = new Critical(self::$value); 20 | } 21 | 22 | public function testGetName() 23 | { 24 | $this->assertSame(self::$name, $this->parameter->getName()); 25 | } 26 | 27 | public function testGetValue() 28 | { 29 | $this->assertSame(self::$value, $this->parameter->getValue()); 30 | } 31 | 32 | public function testSetValue() 33 | { 34 | $newValue = 'NewValue'; 35 | 36 | $this->parameter->setValue($newValue); 37 | $this->assertSame([$newValue], $this->parameter->getValue()); 38 | } 39 | 40 | public function testAddClaim() 41 | { 42 | $parameter = new Custom('foo', 'bar'); 43 | 44 | $this->parameter->addParameter($parameter); 45 | $expectedValue = [self::$value[0], 'foo']; 46 | 47 | $this->assertSame($expectedValue, $this->parameter->getValue()); 48 | 49 | $this->parameter->addParameter($parameter); 50 | $this->assertSame($expectedValue, $this->parameter->getValue(), 'Add parameter duplicates claims'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/HeaderParameter/CustomTest.php: -------------------------------------------------------------------------------- 1 | parameter = new Custom(self::$name, self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testSetName() 26 | { 27 | $newValue = 'baz'; 28 | 29 | $this->parameter->setName($newValue); 30 | 31 | $this->assertSame($newValue, $this->parameter->getName()); 32 | } 33 | 34 | public function testGetValue() 35 | { 36 | $this->assertSame(self::$value, $this->parameter->getValue()); 37 | } 38 | 39 | public function testSetValue() 40 | { 41 | $newValue = 'NewValue'; 42 | 43 | $this->parameter->setValue($newValue); 44 | $this->assertSame($newValue, $this->parameter->getValue()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/HeaderParameter/FactoryTest.php: -------------------------------------------------------------------------------- 1 | 'Emarref\Jwt\HeaderParameter\Algorithm', 9 | ContentType::NAME => 'Emarref\Jwt\HeaderParameter\ContentType', 10 | Critical::NAME => 'Emarref\Jwt\HeaderParameter\Critical', 11 | JsonWebKey::NAME => 'Emarref\Jwt\HeaderParameter\JsonWebKey', 12 | JwkSetUrl::NAME => 'Emarref\Jwt\HeaderParameter\JwkSetUrl', 13 | KeyId::NAME => 'Emarref\Jwt\HeaderParameter\KeyId', 14 | Type::NAME => 'Emarref\Jwt\HeaderParameter\Type', 15 | X509CertificateChain::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateChain', 16 | X509CertificateSha1Thumbprint::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateSha1Thumbprint', 17 | X509CertificateSha256Thumbprint::NAME => 'Emarref\Jwt\HeaderParameter\X509CertificateSha256Thumbprint', 18 | X509Url::NAME => 'Emarref\Jwt\HeaderParameter\X509Url', 19 | ]; 20 | 21 | /** 22 | * @var Factory 23 | */ 24 | private $factory; 25 | 26 | public function setUp() 27 | { 28 | $this->factory = new Factory(); 29 | } 30 | 31 | public function testGetAlgorithm() 32 | { 33 | $this->assertInstanceOf(self::$classMap[Algorithm::NAME], $this->factory->get(Algorithm::NAME)); 34 | } 35 | 36 | public function testGetContentType() 37 | { 38 | $this->assertInstanceOf(self::$classMap[ContentType::NAME], $this->factory->get(ContentType::NAME)); 39 | } 40 | 41 | public function testGetCritical() 42 | { 43 | $this->assertInstanceOf(self::$classMap[Critical::NAME], $this->factory->get(Critical::NAME)); 44 | } 45 | 46 | public function testGetJsonWebKey() 47 | { 48 | $this->assertInstanceOf(self::$classMap[JsonWebKey::NAME], $this->factory->get(JsonWebKey::NAME)); 49 | } 50 | 51 | public function testGetJwkSetUrl() 52 | { 53 | $this->assertInstanceOf(self::$classMap[JwkSetUrl::NAME], $this->factory->get(JwkSetUrl::NAME)); 54 | } 55 | 56 | public function testGetKeyId() 57 | { 58 | $this->assertInstanceOf(self::$classMap[KeyId::NAME], $this->factory->get(KeyId::NAME)); 59 | } 60 | 61 | public function testGetType() 62 | { 63 | $this->assertInstanceOf(self::$classMap[Type::NAME], $this->factory->get(Type::NAME)); 64 | } 65 | 66 | public function testGetX509CertificateChain() 67 | { 68 | $this->assertInstanceOf(self::$classMap[X509CertificateChain::NAME], $this->factory->get(X509CertificateChain::NAME)); 69 | } 70 | 71 | public function testGetX509CertificateSha1Thumbprint() 72 | { 73 | $this->assertInstanceOf(self::$classMap[X509CertificateSha1Thumbprint::NAME], $this->factory->get(X509CertificateSha1Thumbprint::NAME)); 74 | } 75 | 76 | public function testGetX509CertificateSha256Thumbprint() 77 | { 78 | $this->assertInstanceOf(self::$classMap[X509CertificateSha256Thumbprint::NAME], $this->factory->get(X509CertificateSha256Thumbprint::NAME)); 79 | } 80 | 81 | public function testGetX509Url() 82 | { 83 | $this->assertInstanceOf(self::$classMap[X509Url::NAME], $this->factory->get(X509Url::NAME)); 84 | } 85 | 86 | public function testGetCustom() 87 | { 88 | $this->assertInstanceOf('Emarref\Jwt\HeaderParameter\Custom', $this->factory->get('foo')); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test/HeaderParameter/JsonWebKeyTest.php: -------------------------------------------------------------------------------- 1 | parameter = new JsonWebKey(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/JwkSetUrlTest.php: -------------------------------------------------------------------------------- 1 | parameter = new JwkSetUrl(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/KeyIdTest.php: -------------------------------------------------------------------------------- 1 | parameter = new KeyId(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/TypeTest.php: -------------------------------------------------------------------------------- 1 | parameter = new Type(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/X509CertificateChainTest.php: -------------------------------------------------------------------------------- 1 | parameter = new X509CertificateChain(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/X509CertificateSha1ThumbprintTest.php: -------------------------------------------------------------------------------- 1 | parameter = new X509CertificateSha1Thumbprint(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/X509CertificateSha256ThumbprintTest.php: -------------------------------------------------------------------------------- 1 | parameter = new X509CertificateSha256Thumbprint(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/HeaderParameter/X509UrlTest.php: -------------------------------------------------------------------------------- 1 | parameter = new X509Url(self::$value); 18 | } 19 | 20 | public function testGetName() 21 | { 22 | $this->assertSame(self::$name, $this->parameter->getName()); 23 | } 24 | 25 | public function testGetValue() 26 | { 27 | $this->assertSame(self::$value, $this->parameter->getValue()); 28 | } 29 | 30 | public function testSetValue() 31 | { 32 | $newValue = 'NewValue'; 33 | 34 | $this->parameter->setValue($newValue); 35 | $this->assertSame($newValue, $this->parameter->getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Serialization/CompactTest.php: -------------------------------------------------------------------------------- 1 | encoding = $this->getMockBuilder('Emarref\Jwt\Encoding\Base64')->getMock(); 34 | 35 | $this->headerParameterFactory = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Factory')->getMock(); 36 | 37 | $this->claimFactory = $this->getMockBuilder('Emarref\Jwt\Claim\Factory')->getMock(); 38 | 39 | $this->serializer = new Compact($this->encoding, $this->headerParameterFactory, $this->claimFactory); 40 | } 41 | 42 | public function testDeserialize() 43 | { 44 | $jwt = 'a.b.c'; 45 | 46 | // Configure encoding 47 | 48 | $this->encoding->expects($this->at(0)) 49 | ->method('decode') 50 | ->with('a') 51 | ->will($this->returnValue('{"a":"1"}')); 52 | 53 | $this->encoding->expects($this->at(1)) 54 | ->method('decode') 55 | ->with('b') 56 | ->will($this->returnValue('{"b":"2"}')); 57 | 58 | $this->encoding->expects($this->at(2)) 59 | ->method('decode') 60 | ->with('c') 61 | ->will($this->returnValue('c')); 62 | 63 | // Configure headers 64 | 65 | $headerParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Custom') 66 | ->getMock(); 67 | 68 | $headerParameter->expects($this->once()) 69 | ->method('setValue') 70 | ->with('1'); 71 | 72 | $headerParameter->expects($this->once()) 73 | ->method('getValue') 74 | ->will($this->returnValue('1')); 75 | 76 | $headerParameter->expects($this->exactly(2)) 77 | ->method('getName') 78 | ->will($this->returnValue('a')); 79 | 80 | $this->headerParameterFactory->expects($this->once()) 81 | ->method('get') 82 | ->with('a') 83 | ->will($this->returnValue($headerParameter)); 84 | 85 | // Configure claims 86 | 87 | $claim = $this->getMockBuilder('Emarref\Jwt\Claim\PrivateClaim') 88 | ->getMock(); 89 | 90 | $claim->expects($this->once()) 91 | ->method('setValue') 92 | ->with('2'); 93 | 94 | $claim->expects($this->once()) 95 | ->method('getValue') 96 | ->will($this->returnValue('2')); 97 | 98 | $claim->expects($this->exactly(2)) 99 | ->method('getName') 100 | ->will($this->returnValue('b')); 101 | 102 | $this->claimFactory->expects($this->once()) 103 | ->method('get') 104 | ->with('b') 105 | ->will($this->returnValue($claim)); 106 | 107 | // Assert 108 | 109 | $token = $this->serializer->deserialize($jwt); 110 | 111 | $this->assertSame('{"a":"1"}', $token->getHeader()->jsonSerialize()); 112 | $this->assertSame('{"b":"2"}', $token->getPayload()->jsonSerialize()); 113 | $this->assertSame('c', $token->getSignature()); 114 | } 115 | 116 | 117 | /** 118 | * @expectedException \InvalidArgumentException 119 | * @expectedExceptionMessage Not a valid JWT string passed for deserialization 120 | */ 121 | public function testDeserializationWithEmptyToken() 122 | { 123 | $token = ''; 124 | $this->serializer->deserialize($token); 125 | } 126 | 127 | /** 128 | * @expectedException \InvalidArgumentException 129 | * @expectedExceptionMessage Not a valid header of JWT string passed for deserialization 130 | */ 131 | public function testDeserializationTokenWithInvalidHeader() 132 | { 133 | $token = 'header.payload.signature'; 134 | $this->encoding->expects($this->at(0)) 135 | ->method('decode') 136 | ->with('header') 137 | ->will($this->returnValue('{"invalid"}')); 138 | 139 | $this->serializer->deserialize($token); 140 | } 141 | 142 | /** 143 | * @expectedException \InvalidArgumentException 144 | * @expectedExceptionMessage Not a valid payload of JWT string passed for deserialization 145 | */ 146 | public function testDeserializationTokenWithInvalidPayload() 147 | { 148 | $token = 'header.payload.signature'; 149 | $this->encoding->expects($this->at(0)) 150 | ->method('decode') 151 | ->with('header') 152 | ->will($this->returnValue('{"header_field":"valid_header"}')); 153 | 154 | $this->encoding->expects($this->at(1)) 155 | ->method('decode') 156 | ->with('payload') 157 | ->will($this->returnValue('{"invalid"}')); 158 | 159 | $this->encoding->expects($this->at(2)) 160 | ->method('decode') 161 | ->with('signature') 162 | ->will($this->returnValue('{"signature_field":"valid_signature"}')); 163 | 164 | $headerParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Custom') 165 | ->getMock(); 166 | 167 | $this->headerParameterFactory->expects($this->once()) 168 | ->method('get') 169 | ->with('header_field') 170 | ->will($this->returnValue($headerParameter)); 171 | 172 | $this->serializer->deserialize($token); 173 | } 174 | 175 | public function testDeserializationTokenWithoutSignature() 176 | { 177 | $token = 'header.payload'; 178 | $this->encoding->expects($this->at(0)) 179 | ->method('decode') 180 | ->with('header') 181 | ->will($this->returnValue('{"header_field":"valid_header"}')); 182 | 183 | $this->encoding->expects($this->at(1)) 184 | ->method('decode') 185 | ->with('payload') 186 | ->will($this->returnValue('{}')); 187 | 188 | $this->encoding->expects($this->at(2)) 189 | ->method('decode') 190 | ->with(null) 191 | ->will($this->returnValue(null)); 192 | 193 | $headerParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Custom') 194 | ->getMock(); 195 | 196 | $this->headerParameterFactory->expects($this->once()) 197 | ->method('get') 198 | ->with('header_field') 199 | ->will($this->returnValue($headerParameter)); 200 | 201 | $token = $this->serializer->deserialize($token); 202 | 203 | $this->assertNull($token->getSignature()); 204 | } 205 | 206 | public function testSerialize() 207 | { 208 | // Configure payload 209 | 210 | $headerParameters = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 211 | 212 | $headerParameters->expects($this->once()) 213 | ->method('jsonSerialize') 214 | ->will($this->returnValue('{"a":"1"}')); 215 | 216 | $header = $this->getMockBuilder('Emarref\Jwt\Token\Header')->getMock(); 217 | 218 | $header->expects($this->once()) 219 | ->method('getParameters') 220 | ->will($this->returnValue($headerParameters)); 221 | 222 | // Configure payload 223 | 224 | $claims = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 225 | 226 | $claims->expects($this->once()) 227 | ->method('jsonSerialize') 228 | ->will($this->returnValue('{"b":"2"}')); 229 | 230 | $payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 231 | 232 | $payload->expects($this->once()) 233 | ->method('getClaims') 234 | ->will($this->returnValue($claims)); 235 | 236 | // Configure token 237 | 238 | $token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 239 | 240 | $token->expects($this->once()) 241 | ->method('getHeader') 242 | ->will($this->returnValue($header)); 243 | 244 | $token->expects($this->once()) 245 | ->method('getPayload') 246 | ->will($this->returnValue($payload)); 247 | 248 | $token->expects($this->once()) 249 | ->method('getSignature') 250 | ->will($this->returnValue('c')); 251 | 252 | // Configure encoding 253 | 254 | $this->encoding->expects($this->exactly(3)) 255 | ->method('encode') 256 | ->will($this->returnValueMap([ 257 | ['{"a":"1"}', 'a'], 258 | ['{"b":"2"}', 'b'], 259 | ['c', 'c'], 260 | ])); 261 | 262 | $jwt = $this->serializer->serialize($token); 263 | 264 | $this->assertSame('a.b.c', $jwt); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /test/Signature/JwsTest.php: -------------------------------------------------------------------------------- 1 | algorithm = $this->getMockBuilder('Emarref\Jwt\Algorithm\None')->getMock(); 32 | 33 | $this->encryption = $this->getMockBuilder('Emarref\Jwt\Encryption\Symmetric') 34 | ->setConstructorArgs([$this->algorithm]) 35 | ->getMock(); 36 | 37 | $this->encoder = $this->getMockBuilder('Emarref\Jwt\Encoding\Base64')->getMock(); 38 | 39 | $this->signer = new Jws($this->encryption, $this->encoder); 40 | } 41 | 42 | public function testSign() 43 | { 44 | $expectedSignature = 'foobar'; 45 | 46 | // Configure payload 47 | 48 | $headerParameters = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 49 | 50 | $headerParameters->expects($this->once()) 51 | ->method('jsonSerialize'); 52 | 53 | $this->encoder->expects($this->at(0)) 54 | ->method('encode'); 55 | 56 | $header = $this->getMockBuilder('Emarref\Jwt\Token\Header')->getMock(); 57 | 58 | $header->expects($this->once()) 59 | ->method('getParameters') 60 | ->will($this->returnValue($headerParameters)); 61 | 62 | // Configure payload 63 | 64 | $claims = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 65 | 66 | $claims->expects($this->once()) 67 | ->method('jsonSerialize'); 68 | 69 | $payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 70 | 71 | $payload->expects($this->once()) 72 | ->method('getClaims') 73 | ->will($this->returnValue($claims)); 74 | 75 | $this->encoder->expects($this->at(1)) 76 | ->method('encode'); 77 | 78 | // Configure token 79 | 80 | $token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 81 | 82 | $token->expects($this->once()) 83 | ->method('getHeader') 84 | ->will($this->returnValue($header)); 85 | 86 | $token->expects($this->once()) 87 | ->method('getPayload') 88 | ->will($this->returnValue($payload)); 89 | 90 | $this->encryption->expects($this->once()) 91 | ->method('getAlgorithmName') 92 | ->will($this->returnValue('alg')); 93 | 94 | $this->encryption->expects($this->once()) 95 | ->method('encrypt') 96 | ->will($this->returnValue($expectedSignature)); 97 | 98 | $token->expects($this->once()) 99 | ->method('addHeader') 100 | ->with(new Algorithm('alg')); 101 | 102 | $token->expects($this->once()) 103 | ->method('setSignature') 104 | ->with($expectedSignature); 105 | 106 | $this->signer->sign($token); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /test/Token/HeaderStub.php: -------------------------------------------------------------------------------- 1 | propertyList = $propertyList; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Token/HeaderTest.php: -------------------------------------------------------------------------------- 1 | parameters = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 22 | $this->header = new HeaderStub($this->parameters); 23 | } 24 | 25 | public function testSetParameter() 26 | { 27 | $parameter = new HeaderParameter\Custom('name', 'value'); 28 | 29 | $this->parameters->expects($this->once()) 30 | ->method('setProperty') 31 | ->with($parameter); 32 | 33 | $this->header->setParameter($parameter); 34 | } 35 | 36 | public function testSetCriticalParameter() 37 | { 38 | $parameter = new HeaderParameter\Custom('name', 'value'); 39 | 40 | $this->parameters->expects($this->exactly(2)) 41 | ->method('setProperty'); 42 | 43 | $this->parameters->expects($this->at(0)) 44 | ->method('setProperty') 45 | ->with($parameter); 46 | 47 | $this->parameters->expects($this->once()) 48 | ->method('getIterator') 49 | ->will($this->returnValue(new \ArrayObject([$parameter]))); 50 | 51 | $this->header->setParameter($parameter, true); 52 | } 53 | 54 | public function testFindParameterByName() 55 | { 56 | $parameter = new HeaderParameter\Custom('name', 'value'); 57 | 58 | $this->parameters->expects($this->exactly(2)) 59 | ->method('getIterator') 60 | ->will($this->returnValue(new \ArrayObject([$parameter]))); 61 | 62 | $this->assertSame($parameter, $this->header->findParameterByName('name')); 63 | $this->assertNull($this->header->findParameterByName('none')); 64 | } 65 | 66 | public function testGetParameters() 67 | { 68 | $this->assertSame($this->parameters, $this->header->getParameters()); 69 | } 70 | 71 | public function testJsonSerialize() 72 | { 73 | $expectedJson = '{"whatever":true}'; 74 | 75 | $this->parameters->expects($this->once()) 76 | ->method('jsonSerialize') 77 | ->will($this->returnValue($expectedJson)); 78 | 79 | $this->assertSame($expectedJson, $this->header->jsonSerialize()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/Token/PayloadStub.php: -------------------------------------------------------------------------------- 1 | propertyList = $propertyList; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Token/PayloadTest.php: -------------------------------------------------------------------------------- 1 | claims = $this->getMockBuilder('Emarref\Jwt\Token\PropertyList')->getMock(); 22 | $this->payload = new PayloadStub($this->claims); 23 | } 24 | 25 | public function testSetClaim() 26 | { 27 | $claim = new Claim\PrivateClaim('name', 'value'); 28 | 29 | $this->claims->expects($this->once()) 30 | ->method('setProperty') 31 | ->with($claim); 32 | 33 | $this->payload->setClaim($claim); 34 | } 35 | 36 | public function testFindClaimByName() 37 | { 38 | $claim = new Claim\PrivateClaim('name', 'value'); 39 | 40 | $this->claims->expects($this->exactly(2)) 41 | ->method('getIterator') 42 | ->will($this->returnValue(new \ArrayObject([$claim]))); 43 | 44 | $this->assertSame($claim, $this->payload->findClaimByName('name')); 45 | $this->assertNull($this->payload->findClaimByName('none')); 46 | } 47 | 48 | public function testGetClaims() 49 | { 50 | $this->assertSame($this->claims, $this->payload->getClaims()); 51 | } 52 | 53 | public function testJsonSerialize() 54 | { 55 | $expectedJson = '{"whatever":true}'; 56 | 57 | $this->claims->expects($this->once()) 58 | ->method('jsonSerialize') 59 | ->will($this->returnValue($expectedJson)); 60 | 61 | $this->assertSame($expectedJson, $this->payload->jsonSerialize()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/Token/PropertyListStub.php: -------------------------------------------------------------------------------- 1 | properties = $properties; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Token/PropertyListTest.php: -------------------------------------------------------------------------------- 1 | properties = $this->getMockBuilder('\ArrayObject')->getMock(); 20 | 21 | $this->propertyList = new PropertyListStub($this->properties); 22 | } 23 | 24 | public function testSetProperty() 25 | { 26 | $property = new PropertyStub(); 27 | 28 | $this->properties->expects($this->once()) 29 | ->method('offsetSet') 30 | ->with($property->getName(), $property); 31 | 32 | $this->propertyList->setProperty($property); 33 | 34 | return $property; 35 | } 36 | 37 | public function testJsonSerialize() 38 | { 39 | $expectedJson = '{"one":"11","two":"2"}'; 40 | 41 | $properties = new \ArrayIterator([ 42 | new PropertyStub('one', '1'), 43 | new PropertyStub('one', '11'), // Latter takes precedence 44 | new PropertyStub('two', '2'), 45 | new PropertyStub('three', ''), // Blank value ignored 46 | new PropertyStub('', '4'), // Blank name ignored 47 | ]); 48 | 49 | $this->properties->expects($this->once()) 50 | ->method('getIterator') 51 | ->will($this->returnValue($properties)); 52 | 53 | $this->assertSame($expectedJson, $this->propertyList->jsonSerialize()); 54 | } 55 | 56 | public function testGetIterator() 57 | { 58 | $this->assertSame($this->properties, $this->propertyList->getIterator()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/Token/PropertyStub.php: -------------------------------------------------------------------------------- 1 | setName($name); 24 | $this->setValue($value); 25 | } 26 | 27 | /** 28 | * @return string 29 | */ 30 | public function getName() 31 | { 32 | return $this->name; 33 | } 34 | 35 | /** 36 | * @param string $name 37 | * @return $this 38 | */ 39 | public function setName($name) 40 | { 41 | $this->name = $name; 42 | return $this; 43 | } 44 | 45 | /** 46 | * @return mixed 47 | */ 48 | public function getValue() 49 | { 50 | return $this->value; 51 | } 52 | 53 | /** 54 | * @param mixed 55 | * @return $this 56 | */ 57 | public function setValue($value) 58 | { 59 | $this->value = $value; 60 | return $this; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/Verification/AudienceVerifierTest.php: -------------------------------------------------------------------------------- 1 | payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 22 | 23 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 24 | } 25 | 26 | /** 27 | * @expectedException \InvalidArgumentException 28 | * @expectedExceptionMessage Cannot verify invalid audience value. 29 | */ 30 | public function testInvalidAudience() 31 | { 32 | new AudienceVerifier(new \stdClass()); 33 | } 34 | 35 | public function testNoAudienceInToken() 36 | { 37 | $this->token->expects($this->once()) 38 | ->method('getPayload') 39 | ->will($this->returnValue($this->payload)); 40 | 41 | $this->payload->expects($this->once()) 42 | ->method('findClaimByName') 43 | ->with(Claim\Audience::NAME) 44 | ->will($this->returnValue(null)); 45 | 46 | $verifier = new AudienceVerifier(); 47 | $verifier->verify($this->token); 48 | } 49 | 50 | /** 51 | * @expectedException \Emarref\Jwt\Exception\InvalidAudienceException 52 | * @expectedExceptionMessage Audience is invalid. 53 | */ 54 | public function testInvalidAudienceInToken() 55 | { 56 | $expectedAudience = 'urn://myaudience'; 57 | 58 | $audienceClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Audience')->getMock(); 59 | 60 | $audienceClaim->expects($this->once()) 61 | ->method('getValue') 62 | ->will($this->returnValue($expectedAudience)); 63 | 64 | $this->payload->expects($this->once()) 65 | ->method('findClaimByName') 66 | ->with(Claim\Audience::NAME) 67 | ->will($this->returnValue($audienceClaim)); 68 | 69 | $this->token->expects($this->once()) 70 | ->method('getPayload') 71 | ->will($this->returnValue($this->payload)); 72 | 73 | $verifier = new AudienceVerifier('foobar'); 74 | $verifier->verify($this->token); 75 | } 76 | 77 | public function testArrayAudience() 78 | { 79 | $audienceClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Audience')->getMock(); 80 | 81 | $audienceClaim->expects($this->once()) 82 | ->method('getValue') 83 | ->will($this->returnValue(['urn://audienceone', 'urn://audiencetwo'])); 84 | 85 | $this->payload->expects($this->once()) 86 | ->method('findClaimByName') 87 | ->with(Claim\Audience::NAME) 88 | ->will($this->returnValue($audienceClaim)); 89 | 90 | $this->token->expects($this->once()) 91 | ->method('getPayload') 92 | ->will($this->returnValue($this->payload)); 93 | 94 | $verifier = new AudienceVerifier('urn://audienceone'); 95 | $verifier->verify($this->token); 96 | } 97 | 98 | public function testStringAudience() 99 | { 100 | $audienceClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Audience')->getMock(); 101 | 102 | $audienceClaim->expects($this->once()) 103 | ->method('getValue') 104 | ->will($this->returnValue('urn://audienceone')); 105 | 106 | $this->payload->expects($this->once()) 107 | ->method('findClaimByName') 108 | ->with(Claim\Audience::NAME) 109 | ->will($this->returnValue($audienceClaim)); 110 | 111 | $this->token->expects($this->once()) 112 | ->method('getPayload') 113 | ->will($this->returnValue($this->payload)); 114 | 115 | $verifier = new AudienceVerifier('urn://audienceone'); 116 | $verifier->verify($this->token); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /test/Verification/EncryptionVerifierStub.php: -------------------------------------------------------------------------------- 1 | signer = $signer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/Verification/EncryptionVerifierTest.php: -------------------------------------------------------------------------------- 1 | header = $this->getMockBuilder('Emarref\Jwt\Token\Header')->getMock(); 42 | 43 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 44 | 45 | $this->token->expects($this->any()) 46 | ->method('getHeader') 47 | ->will($this->returnValue($this->header)); 48 | 49 | $this->algorithm = $this->getMockBuilder('Emarref\Jwt\Algorithm\None')->getMock(); 50 | 51 | $this->encryption = $this->getMockBuilder('Emarref\Jwt\Encryption\Symmetric') 52 | ->setConstructorArgs([$this->algorithm]) 53 | ->getMock(); 54 | 55 | $this->encoder = $this->getMockBuilder('Emarref\Jwt\Encoding\Base64')->getMock(); 56 | 57 | $this->signer = $this->getMockBuilder('Emarref\Jwt\Signature\Jws') 58 | ->disableOriginalConstructor() 59 | ->getMock(); 60 | } 61 | 62 | /** 63 | * @expectedException \RuntimeException 64 | * @expectedExceptionMessage Algorithm parameter not found in token header. 65 | */ 66 | public function testMissingAlgorithm() 67 | { 68 | $this->header->expects($this->once()) 69 | ->method('findParameterByName') 70 | ->with(HeaderParameter\Algorithm::NAME) 71 | ->will($this->returnValue(null)); 72 | 73 | $verifier = new EncryptionVerifier($this->encryption, $this->encoder); 74 | $verifier->verify($this->token); 75 | } 76 | 77 | /** 78 | * @expectedException \RuntimeException 79 | * @expectedExceptionMessage Cannot use "bar" algorithm to decrypt token encrypted with algorithm "foo". 80 | */ 81 | public function testAlgorithmMismatch() 82 | { 83 | $algorithmParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Algorithm')->getMock(); 84 | 85 | $algorithmParameter->expects($this->exactly(2)) 86 | ->method('getValue') 87 | ->will($this->returnValue('foo')); 88 | 89 | $this->header->expects($this->once()) 90 | ->method('findParameterByName') 91 | ->with(HeaderParameter\Algorithm::NAME) 92 | ->will($this->returnValue($algorithmParameter)); 93 | 94 | $this->encryption->expects($this->exactly(2)) 95 | ->method('getAlgorithmName') 96 | ->will($this->returnValue('bar')); 97 | 98 | $verifier = new EncryptionVerifier($this->encryption, $this->encoder); 99 | $verifier->verify($this->token); 100 | } 101 | 102 | /** 103 | * @expectedException \Emarref\Jwt\Exception\InvalidSignatureException 104 | * @expectedExceptionMessage Signature is invalid. 105 | */ 106 | public function testInvalidSignature() 107 | { 108 | $algorithmParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Algorithm')->getMock(); 109 | 110 | $algorithmParameter->expects($this->once()) 111 | ->method('getValue') 112 | ->will($this->returnValue('foo')); 113 | 114 | $this->header->expects($this->once()) 115 | ->method('findParameterByName') 116 | ->with(HeaderParameter\Algorithm::NAME) 117 | ->will($this->returnValue($algorithmParameter)); 118 | 119 | $this->encryption->expects($this->once()) 120 | ->method('getAlgorithmName') 121 | ->will($this->returnValue('foo')); 122 | 123 | $this->encryption->expects($this->once()) 124 | ->method('verify') 125 | ->will($this->returnValue(false)); 126 | 127 | $this->signer->expects($this->once()) 128 | ->method('getUnsignedValue') 129 | ->will($this->returnValue('foo')); 130 | 131 | $this->token->expects($this->once()) 132 | ->method('getSignature') 133 | ->will($this->returnValue('bar')); 134 | 135 | $verifier = new EncryptionVerifierStub($this->encryption, $this->encoder, $this->signer); 136 | $verifier->verify($this->token); 137 | } 138 | 139 | public function testValidSignature() 140 | { 141 | $algorithmParameter = $this->getMockBuilder('Emarref\Jwt\HeaderParameter\Algorithm')->getMock(); 142 | 143 | $algorithmParameter->expects($this->once()) 144 | ->method('getValue') 145 | ->will($this->returnValue('foo')); 146 | 147 | $this->header->expects($this->once()) 148 | ->method('findParameterByName') 149 | ->with(HeaderParameter\Algorithm::NAME) 150 | ->will($this->returnValue($algorithmParameter)); 151 | 152 | $this->encryption->expects($this->once()) 153 | ->method('getAlgorithmName') 154 | ->will($this->returnValue('foo')); 155 | 156 | $this->encryption->expects($this->once()) 157 | ->method('verify') 158 | ->will($this->returnValue(true)); 159 | 160 | $this->signer->expects($this->once()) 161 | ->method('getUnsignedValue') 162 | ->will($this->returnValue('bar')); 163 | 164 | $this->token->expects($this->once()) 165 | ->method('getSignature') 166 | ->will($this->returnValue('bar')); 167 | 168 | $verifier = new EncryptionVerifierStub($this->encryption, $this->encoder, $this->signer); 169 | $verifier->verify($this->token); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /test/Verification/ExpirationVerifierTest.php: -------------------------------------------------------------------------------- 1 | payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 25 | 26 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 27 | 28 | $this->token->expects($this->any()) 29 | ->method('getPayload') 30 | ->will($this->returnValue($this->payload)); 31 | 32 | $this->verifier = new ExpirationVerifier(); 33 | } 34 | 35 | public function testMissingExpiry() 36 | { 37 | $this->payload->expects($this->once()) 38 | ->method('findClaimByName') 39 | ->will($this->returnValue(null)); 40 | 41 | $this->verifier->verify($this->token); 42 | } 43 | 44 | /** 45 | * @expectedException \Emarref\Jwt\Exception\ExpiredException 46 | * @expectedExceptionMessage Token expired at "Sat, 08 Nov 2014 00:00:00 +0000" 47 | */ 48 | public function testExpired() 49 | { 50 | $dateTime = new \DateTime('Sat, 08 Nov 2014 00:00:00 +0000'); 51 | 52 | $expirationClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Expiration')->getMock(); 53 | 54 | $expirationClaim->expects($this->exactly(3)) 55 | ->method('getValue') 56 | ->will($this->returnValue($dateTime->getTimestamp())); 57 | 58 | $this->payload->expects($this->once()) 59 | ->method('findClaimByName') 60 | ->will($this->returnValue($expirationClaim)); 61 | 62 | $this->verifier->verify($this->token); 63 | } 64 | 65 | /** 66 | * @expectedException \InvalidArgumentException 67 | * @expectedExceptionMessage Invalid expiration timestamp "foobar" 68 | */ 69 | public function testUnexpectedValue() 70 | { 71 | $expirationClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Expiration')->getMock(); 72 | 73 | $expirationClaim->expects($this->exactly(3)) 74 | ->method('getValue') 75 | ->will($this->returnValue('foobar')); 76 | 77 | $this->payload->expects($this->once()) 78 | ->method('findClaimByName') 79 | ->will($this->returnValue($expirationClaim)); 80 | 81 | $this->verifier->verify($this->token); 82 | } 83 | 84 | public function testValid() 85 | { 86 | $future = new \DateTime('5 minutes', new \DateTimeZone('UTC')); 87 | 88 | $expirationClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Expiration')->getMock(); 89 | 90 | $expirationClaim->expects($this->once()) 91 | ->method('getValue') 92 | ->will($this->returnValue($future->getTimestamp())); 93 | 94 | $this->payload->expects($this->once()) 95 | ->method('findClaimByName') 96 | ->will($this->returnValue($expirationClaim)); 97 | 98 | $this->verifier->verify($this->token); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /test/Verification/IssuerVerifierTest.php: -------------------------------------------------------------------------------- 1 | payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 22 | 23 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 24 | } 25 | 26 | /** 27 | * @expectedException \InvalidArgumentException 28 | * @expectedExceptionMessage Cannot verify invalid issuer value. 29 | */ 30 | public function testInvalidIssuer() 31 | { 32 | new IssuerVerifier(new \stdClass()); 33 | } 34 | 35 | public function testNoIssuer() 36 | { 37 | $this->token->expects($this->once()) 38 | ->method('getPayload') 39 | ->will($this->returnValue($this->payload)); 40 | 41 | $this->payload->expects($this->once()) 42 | ->method('findClaimByName') 43 | ->with(Claim\Issuer::NAME) 44 | ->will($this->returnValue(null)); 45 | 46 | $verifier = new IssuerVerifier(); 47 | $verifier->verify($this->token); 48 | } 49 | 50 | /** 51 | * @expectedException \Emarref\Jwt\Exception\InvalidIssuerException 52 | * @expectedExceptionMessage Issuer is invalid. 53 | */ 54 | public function testIssuerInPayloadOnly() 55 | { 56 | $issuerClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Issuer') 57 | ->getMock(); 58 | 59 | $issuerClaim->expects($this->once()) 60 | ->method('getValue') 61 | ->will($this->returnValue('an_issuer')); 62 | 63 | $this->token->expects($this->once()) 64 | ->method('getPayload') 65 | ->will($this->returnValue($this->payload)); 66 | 67 | $this->payload->expects($this->once()) 68 | ->method('findClaimByName') 69 | ->with(Claim\Issuer::NAME) 70 | ->will($this->returnValue($issuerClaim)); 71 | 72 | $verifier = new IssuerVerifier(); 73 | $verifier->verify($this->token); 74 | } 75 | 76 | /** 77 | * @expectedException \Emarref\Jwt\Exception\InvalidIssuerException 78 | * @expectedExceptionMessage Issuer is invalid. 79 | */ 80 | public function testIssuerInContextOnly() 81 | { 82 | $this->token->expects($this->once()) 83 | ->method('getPayload') 84 | ->will($this->returnValue($this->payload)); 85 | 86 | $this->payload->expects($this->once()) 87 | ->method('findClaimByName') 88 | ->with(Claim\Issuer::NAME) 89 | ->will($this->returnValue(null)); 90 | 91 | $verifier = new IssuerVerifier('an_issuer'); 92 | $verifier->verify($this->token); 93 | } 94 | 95 | /** 96 | * @expectedException \Emarref\Jwt\Exception\InvalidIssuerException 97 | * @expectedExceptionMessage Issuer is invalid. 98 | */ 99 | public function testIssuerMismatch() 100 | { 101 | $issuerClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Issuer') 102 | ->getMock(); 103 | 104 | $issuerClaim->expects($this->once()) 105 | ->method('getValue') 106 | ->will($this->returnValue('an_issuer')); 107 | 108 | $this->token->expects($this->once()) 109 | ->method('getPayload') 110 | ->will($this->returnValue($this->payload)); 111 | 112 | $this->payload->expects($this->once()) 113 | ->method('findClaimByName') 114 | ->with(Claim\Issuer::NAME) 115 | ->will($this->returnValue($issuerClaim)); 116 | 117 | $verifier = new IssuerVerifier('some_other_issuer'); 118 | $verifier->verify($this->token); 119 | } 120 | 121 | public function testSuccess() 122 | { 123 | $issuerClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Issuer') 124 | ->getMock(); 125 | 126 | $issuerClaim->expects($this->once()) 127 | ->method('getValue') 128 | ->will($this->returnValue('an_issuer')); 129 | 130 | $this->token->expects($this->once()) 131 | ->method('getPayload') 132 | ->will($this->returnValue($this->payload)); 133 | 134 | $this->payload->expects($this->once()) 135 | ->method('findClaimByName') 136 | ->with(Claim\Issuer::NAME) 137 | ->will($this->returnValue($issuerClaim)); 138 | 139 | $verifier = new IssuerVerifier('an_issuer'); 140 | $verifier->verify($this->token); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /test/Verification/NotBeforeVerifierTest.php: -------------------------------------------------------------------------------- 1 | payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 27 | 28 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 29 | 30 | $this->token->expects($this->any()) 31 | ->method('getPayload') 32 | ->will($this->returnValue($this->payload)); 33 | 34 | $this->verifier = new NotBeforeVerifier(); 35 | } 36 | 37 | public function testMissingNotBefore() 38 | { 39 | $this->payload->expects($this->once()) 40 | ->method('findClaimByName') 41 | ->with(NotBefore::NAME) 42 | ->will($this->returnValue(null)); 43 | 44 | $this->verifier->verify($this->token); 45 | } 46 | 47 | /** 48 | * @expectedException \Emarref\Jwt\Exception\TooEarlyException 49 | * @expectedExceptionMessageRegExp /Token must not be processed before "[\w,:+\d ]+"/ 50 | */ 51 | public function testNotBefore() 52 | { 53 | $dateTime = new \DateTime('1 day'); 54 | 55 | $notBeforeClaim = $this->getMockBuilder('Emarref\Jwt\Claim\NotBefore')->getMock(); 56 | 57 | $notBeforeClaim->expects($this->exactly(3)) 58 | ->method('getValue') 59 | ->will($this->returnValue($dateTime->getTimestamp())); 60 | 61 | $this->payload->expects($this->once()) 62 | ->method('findClaimByName') 63 | ->with(NotBefore::NAME) 64 | ->will($this->returnValue($notBeforeClaim)); 65 | 66 | $this->verifier->verify($this->token); 67 | } 68 | 69 | /** 70 | * @expectedException \InvalidArgumentException 71 | * @expectedExceptionMessage Invalid not before timestamp "foobar" 72 | */ 73 | public function testUnexpectedValue() 74 | { 75 | $notBeforeClaim = $this->getMockBuilder('Emarref\Jwt\Claim\NotBefore')->getMock(); 76 | 77 | $notBeforeClaim->expects($this->exactly(2)) 78 | ->method('getValue') 79 | ->will($this->returnValue('foobar')); 80 | 81 | $this->payload->expects($this->once()) 82 | ->method('findClaimByName') 83 | ->with(NotBefore::NAME) 84 | ->will($this->returnValue($notBeforeClaim)); 85 | 86 | $this->verifier->verify($this->token); 87 | } 88 | 89 | public function testValid() 90 | { 91 | $past = new \DateTime('5 minutes ago', new \DateTimeZone('UTC')); 92 | 93 | $notBeforeClaim = $this->getMockBuilder('Emarref\Jwt\Claim\NotBefore')->getMock(); 94 | 95 | $notBeforeClaim->expects($this->exactly(2)) 96 | ->method('getValue') 97 | ->will($this->returnValue($past->getTimestamp())); 98 | 99 | $this->payload->expects($this->once()) 100 | ->method('findClaimByName') 101 | ->with(NotBefore::NAME) 102 | ->will($this->returnValue($notBeforeClaim)); 103 | 104 | $this->verifier->verify($this->token); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /test/Verification/SubjectVerifierTest.php: -------------------------------------------------------------------------------- 1 | payload = $this->getMockBuilder('Emarref\Jwt\Token\Payload')->getMock(); 22 | 23 | $this->token = $this->getMockBuilder('Emarref\Jwt\Token')->getMock(); 24 | } 25 | 26 | /** 27 | * @expectedException \InvalidArgumentException 28 | * @expectedExceptionMessage Cannot verify invalid subject value. 29 | */ 30 | public function testInvalidSubject() 31 | { 32 | new SubjectVerifier(new \stdClass()); 33 | } 34 | 35 | public function testNoSubject() 36 | { 37 | $this->token->expects($this->once()) 38 | ->method('getPayload') 39 | ->will($this->returnValue($this->payload)); 40 | 41 | $this->payload->expects($this->once()) 42 | ->method('findClaimByName') 43 | ->with(Claim\Subject::NAME) 44 | ->will($this->returnValue(null)); 45 | 46 | $verifier = new SubjectVerifier(); 47 | $verifier->verify($this->token); 48 | } 49 | 50 | /** 51 | * @expectedException \Emarref\Jwt\Exception\InvalidSubjectException 52 | * @expectedExceptionMessage Subject is invalid. 53 | */ 54 | public function testSubjectInPayloadOnly() 55 | { 56 | $subjectClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Subject') 57 | ->getMock(); 58 | 59 | $subjectClaim->expects($this->once()) 60 | ->method('getValue') 61 | ->will($this->returnValue('a_subject')); 62 | 63 | $this->token->expects($this->once()) 64 | ->method('getPayload') 65 | ->will($this->returnValue($this->payload)); 66 | 67 | $this->payload->expects($this->once()) 68 | ->method('findClaimByName') 69 | ->with(Claim\Subject::NAME) 70 | ->will($this->returnValue($subjectClaim)); 71 | 72 | $verifier = new SubjectVerifier(); 73 | $verifier->verify($this->token); 74 | } 75 | 76 | /** 77 | * @expectedException \Emarref\Jwt\Exception\InvalidSubjectException 78 | * @expectedExceptionMessage Subject is invalid. 79 | */ 80 | public function testSubjectInContextOnly() 81 | { 82 | $this->token->expects($this->once()) 83 | ->method('getPayload') 84 | ->will($this->returnValue($this->payload)); 85 | 86 | $this->payload->expects($this->once()) 87 | ->method('findClaimByName') 88 | ->with(Claim\Subject::NAME) 89 | ->will($this->returnValue(null)); 90 | 91 | $verifier = new SubjectVerifier('a_subject'); 92 | $verifier->verify($this->token); 93 | } 94 | 95 | /** 96 | * @expectedException \Emarref\Jwt\Exception\InvalidSubjectException 97 | * @expectedExceptionMessage Subject is invalid. 98 | */ 99 | public function testSubjectMismatch() 100 | { 101 | $subjectClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Subject') 102 | ->getMock(); 103 | 104 | $subjectClaim->expects($this->once()) 105 | ->method('getValue') 106 | ->will($this->returnValue('a_subject')); 107 | 108 | $this->token->expects($this->once()) 109 | ->method('getPayload') 110 | ->will($this->returnValue($this->payload)); 111 | 112 | $this->payload->expects($this->once()) 113 | ->method('findClaimByName') 114 | ->with(Claim\Subject::NAME) 115 | ->will($this->returnValue($subjectClaim)); 116 | 117 | $verifier = new SubjectVerifier('some_other_subject'); 118 | $verifier->verify($this->token); 119 | } 120 | 121 | public function testSuccess() 122 | { 123 | $subjectClaim = $this->getMockBuilder('Emarref\Jwt\Claim\Subject') 124 | ->getMock(); 125 | 126 | $subjectClaim->expects($this->once()) 127 | ->method('getValue') 128 | ->will($this->returnValue('a_subject')); 129 | 130 | $this->token->expects($this->once()) 131 | ->method('getPayload') 132 | ->will($this->returnValue($this->payload)); 133 | 134 | $this->payload->expects($this->once()) 135 | ->method('findClaimByName') 136 | ->with(Claim\Subject::NAME) 137 | ->will($this->returnValue($subjectClaim)); 138 | 139 | $verifier = new SubjectVerifier('a_subject'); 140 | $verifier->verify($this->token); 141 | } 142 | } 143 | --------------------------------------------------------------------------------