diff --git a/.travis.yml b/.travis.yml index 3715dfa..6dffd6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ before_script: - travis_retry composer install --no-interaction --prefer-source --dev script: - - vendor/bin/phpcs --standard=psr12 src - - vendor/bin/phpstan analyse -l 7 src + - vendor/bin/phpcs --standard=psr12 src tests + - vendor/bin/phpstan analyse -l 7 src tests - vendor/bin/phpmd src text ruleset.xml - vendor/bin/phpunit --coverage-clover=coverage.xml diff --git a/README.md b/README.md index db64d72..2d82049 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,64 @@ # PSR-JWT [![Build Status](https://travis-ci.org/RobDWaller/psr-jwt.svg?branch=master)](https://travis-ci.org/RobDWaller/psr-jwt) [![codecov](https://codecov.io/gh/RobDWaller/psr-jwt/branch/master/graph/badge.svg)](https://codecov.io/gh/RobDWaller/psr-jwt) -A PSR-7 and PSR-15 compliant JSON Web Token Middleware Library. +A PSR-7 and PSR-15 compliant JSON Web Token Middleware Library. Currently in alpha and built on top of [ReallySimpleJWT](https://github.com/RobDWaller/ReallySimpleJWT). -Currently in alpha and built on top of [ReallySimpleJWT](https://github.com/RobDWaller/ReallySimpleJWT). +The library allows you to create JSON Web Tokens and then validate them using PSR-15 compliant middleware which can be added to compatible frameworks. -For more information on JSON Web Tokens please read [RFC 7519](https://tools.ietf.org/html/rfc7519). Also to learn more about how to pass JSON Web Tokens to web applications please read up on bearer token authorization in [RFC 6750](https://tools.ietf.org/html/rfc6750). +For more information on JSON Web Tokens please read [RFC 7519](https://tools.ietf.org/html/rfc7519). Also to learn more about how to pass JSON Web Tokens to web applications please read up on bearer token authorization in [RFC 6750](https://tools.ietf.org/html/rfc6750). + +## Setup + +Via Composer on the command line: + +```bash +composer require rbdwllr/psr-jwt +``` + +Via composer.json: + +```javascript +"require": { + "rbdwllr/psr-jwt": "^0.1" +} +``` + +## Usage + +PSR-JWT can be used with any PSR-7 / PSR-15 compliant framework. Just call the middleware factory method and it will return a middleware instance that exposes two methods, `__invoke()` and `process()`. The later will work with PSR-15 compliant frameworks like Zend Expressive and the former will work with older PSR-7 compliant frameworks like Slim PHP v3. + +```php +\PsrJwt\Factory\JwtAuth::middleware('tokenKey', 'secret'); +``` + +The `tokenKey` is the key required to retrieve the JSON Web Token from a cookie, query parameter or the request body. By default though the library looks for tokens in bearer field of the authorization header. + +The `secret` is the string required to hash the JSON Web Token signature. + +### Slim PHP 3.0 Example Implementation + +```php +// Can be added to any routes file in Slim, often index.php. +$app->get('/jwt', function (Request $request, Response $response) { + $response->getBody()->write("JSON Web Token is Valid!"); + + return $response; +})->add(\PsrJwt\Factory\JwtAuth::middleware('jwt', 'Secret123!456$')); +``` + +### Zend Expressive Example Implementation + +```php +// Add to the config/pipeline.php file. +$app->pipe('/api', \PsrJwt\Factory\JwtAuth::middleware('jwt', '!secReT$123*')); +``` + +### Generate JSON Web Token + +To generate JSON Web Tokens PsrJwt offers a wrapper for the library ReallySimpleJWT. You can create an instance of the ReallySimpleJWT builder by calling the built in factory method. + +```php +\PsrJwt\Factory\Jwt::builder(); +``` + +For more information on creating tokens please read the ReallySimpleJWT documentation. diff --git a/composer.json b/composer.json index 740cdb9..587e581 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "require-dev": { "phpunit/phpunit": "^7.0", "phpstan/phpstan": "^0.10", + "phpstan/phpstan-mockery": "^0.10", "phpmd/phpmd": "2.6.*", "squizlabs/php_codesniffer": "^3.0", "mockery/mockery": "^1.2" diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..939b954 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,2 @@ +includes: + - vendor/phpstan/phpstan-mockery/extension.neon diff --git a/src/Auth/Auth.php b/src/Auth/Auth.php new file mode 100644 index 0000000..82aa10a --- /dev/null +++ b/src/Auth/Auth.php @@ -0,0 +1,29 @@ +code = $code; + + $this->message = $message; + } + + public function getCode(): int + { + return $this->code; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/src/JwtAuthHandler.php b/src/Auth/Authenticate.php similarity index 57% rename from src/JwtAuthHandler.php rename to src/Auth/Authenticate.php index a9400ae..8d7b238 100644 --- a/src/JwtAuthHandler.php +++ b/src/Auth/Authenticate.php @@ -2,19 +2,16 @@ declare(strict_types=1); -namespace PsrJwt; +namespace PsrJwt\Auth; -use PsrJwt\JwtFactory; -use PsrJwt\JwtValidate; -use PsrJwt\JwtParse; -use Psr\Http\Server\RequestHandlerInterface; -use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use ReallySimpleJWT\Exception\ValidateException; -use Nyholm\Psr7\Factory\Psr17Factory; -use Throwable; +use PsrJwt\Factory\Jwt; +use PsrJwt\Auth\Auth; +use PsrJwt\Parser\Parse; +use PsrJwt\Validation\Validate; -class JwtAuthHandler implements RequestHandlerInterface +class Authenticate { private $tokenKey; @@ -27,16 +24,27 @@ public function __construct(string $tokenKey, string $secret) $this->secret = $secret; } - protected function getSecret(): string + public function authenticate(ServerRequestInterface $request): Auth + { + try { + $token = $this->getToken($request); + } catch (ValidateException $e) { + return new Auth(400, 'Bad Request: ' . $e->getMessage()); + } + + return $this->validate($token); + } + + public function getSecret(): string { return $this->secret; } - protected function validate(string $token): ResponseInterface + private function validate(string $token): Auth { - $parse = JwtFactory::parser($token, $this->getSecret()); + $parse = Jwt::parser($token, $this->getSecret()); - $validate = new JwtValidate($parse); + $validate = new Validate($parse); $validationState = $validate->validate(); @@ -48,15 +56,13 @@ protected function validate(string $token): ResponseInterface ); } - private function validationResponse(int $code, string $message): ResponseInterface + private function validationResponse(int $code, string $message): Auth { - $factory = new Psr17Factory(); - if (in_array($code, [1, 2, 3, 4, 5], true)) { - return $factory->createResponse(401, 'Unauthorized: ' . $message); + return new Auth(401, 'Unauthorized: ' . $message); } - return $factory->createResponse(200, 'Ok'); + return new Auth(200, 'Ok'); } private function hasJwt(string $token): bool @@ -64,14 +70,13 @@ private function hasJwt(string $token): bool return !empty($token); } - protected function getToken(ServerRequestInterface $request): string + private function getToken(ServerRequestInterface $request): string { - $parse = new JwtParse(['token_key' => $this->tokenKey]); + $parse = new Parse(['token_key' => $this->tokenKey]); $parse->addParser(\PsrJwt\Parser\Bearer::class); $parse->addParser(\PsrJwt\Parser\Cookie::class); $parse->addParser(\PsrJwt\Parser\Body::class); $parse->addParser(\PsrJwt\Parser\Query::class); - $parse->addParser(\PsrJwt\Parser\Server::class); $token = $parse->findToken($request); @@ -81,16 +86,4 @@ protected function getToken(ServerRequestInterface $request): string throw new ValidateException('JSON Web Token not set.', 11); } - - public function handle(ServerRequestInterface $request): ResponseInterface - { - try { - $token = $this->getToken($request); - } catch (ValidateException $e) { - $factory = new Psr17Factory(); - return $factory->createResponse(400, 'Bad Request: ' . $e->getMessage()); - } - - return $this->validate($token); - } } diff --git a/src/JwtFactory.php b/src/Factory/Jwt.php similarity index 81% rename from src/JwtFactory.php rename to src/Factory/Jwt.php index 69c6a54..26e05bf 100644 --- a/src/JwtFactory.php +++ b/src/Factory/Jwt.php @@ -2,15 +2,15 @@ declare(strict_types=1); -namespace PsrJwt; +namespace PsrJwt\Factory; use ReallySimpleJWT\Build; use ReallySimpleJWT\Validate; use ReallySimpleJWT\Encode; use ReallySimpleJWT\Parse; -use ReallySimpleJWT\Jwt; +use ReallySimpleJWT\Jwt as RSJwt; -class JwtFactory +class Jwt { public static function builder(): Build { @@ -23,7 +23,7 @@ public static function builder(): Build public static function parser(string $token, string $secret): Parse { - $jwt = new Jwt($token, $secret); + $jwt = new RSJwt($token, $secret); return new Parse( $jwt, diff --git a/src/Factory/JwtAuth.php b/src/Factory/JwtAuth.php new file mode 100644 index 0000000..581dcf6 --- /dev/null +++ b/src/Factory/JwtAuth.php @@ -0,0 +1,19 @@ +handler = $handler; - } - - public function __invoke( - ServerRequestInterface $request, - ResponseInterface $response, - callable $next - ): ResponseInterface { - $response = $this->handler->handle($request); - - if ($response->getStatusCode() !== 200) { - return $response; - } - - return $next($request, $response); - } -} diff --git a/src/JwtAuthMiddleware.php b/src/JwtAuthMiddleware.php index ae385f4..dbac2ae 100644 --- a/src/JwtAuthMiddleware.php +++ b/src/JwtAuthMiddleware.php @@ -4,15 +4,51 @@ namespace PsrJwt; +use Nyholm\Psr7\Factory\Psr17Factory; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; +use PsrJwt\Auth\Authenticate; +use PsrJwt\Auth\Auth; class JwtAuthMiddleware implements MiddlewareInterface { + private $authenticate; + + public function __construct(Authenticate $authenticate) + { + $this->authenticate = $authenticate; + } + + public function __invoke( + ServerRequestInterface $request, + ResponseInterface $response, + callable $next + ): ResponseInterface { + $auth = $this->authenticate->authenticate($request); + + if ($auth->getCode() === 200) { + return $next($request, $response); + } + + return $this->failResponse($auth); + } + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - return $handler->handle($request); + $auth = $this->authenticate->authenticate($request); + + if ($auth->getCode() === 200) { + return $handler->handle($request); + } + + return $this->failResponse($auth); + } + + private function failResponse(Auth $auth): ResponseInterface + { + $factory = new Psr17Factory(); + return $factory->createResponse($auth->getCode(), $auth->getMessage()); } } diff --git a/src/JwtParse.php b/src/Parser/Parse.php similarity index 78% rename from src/JwtParse.php rename to src/Parser/Parse.php index 4ad7e10..f1d52bf 100644 --- a/src/JwtParse.php +++ b/src/Parser/Parse.php @@ -2,11 +2,11 @@ declare(strict_types = 1); -namespace PsrJwt; +namespace PsrJwt\Parser; use Psr\Http\Message\ServerRequestInterface; -class JwtParse +class Parse { private $parsers = []; @@ -22,9 +22,14 @@ public function addParser(string $parser): void $this->parsers[] = $parser; } + public function getParsers(): array + { + return $this->parsers; + } + public function findToken(ServerRequestInterface $request): string { - foreach ($this->parsers as $parser) { + foreach ($this->getParsers() as $parser) { $object = new $parser($this->arguments); $token = $object->parse($request); if (!empty($token)) { diff --git a/src/Parser/Server.php b/src/Parser/Server.php deleted file mode 100644 index ab3163f..0000000 --- a/src/Parser/Server.php +++ /dev/null @@ -1,23 +0,0 @@ -arguments = $arguments; - } - - public function parse(ServerRequestInterface $request): string - { - return $request->getServerParams()[$this->arguments['token_key']] ?? ''; - } -} diff --git a/src/JwtValidate.php b/src/Validation/Validate.php similarity index 95% rename from src/JwtValidate.php rename to src/Validation/Validate.php index aa75b23..a2b0f5f 100644 --- a/src/JwtValidate.php +++ b/src/Validation/Validate.php @@ -2,12 +2,12 @@ declare(strict_types = 1); -namespace PsrJwt; +namespace PsrJwt\Validation; use ReallySimpleJWT\Parse; use ReallySimpleJWT\Exception\ValidateException; -class JwtValidate +class Validate { private $parse; diff --git a/tests/Auth/AuthTest.php b/tests/Auth/AuthTest.php new file mode 100644 index 0000000..e6fa1c3 --- /dev/null +++ b/tests/Auth/AuthTest.php @@ -0,0 +1,37 @@ +assertInstanceOf(Auth::class, $auth); + return $auth; + } + + /** + * @depends testAuth + * @covers PsrJwt\Auth\Auth::getCode + */ + public function testGetCode($auth) + { + $this->assertSame(200, $auth->getCode()); + } + + /** + * @depends testAuth + * @covers PsrJwt\Auth\Auth::getMessage + */ + public function testGetMessage($auth) + { + $this->assertSame('Ok', $auth->getMessage()); + } +} diff --git a/tests/Auth/AuthenticateTest.php b/tests/Auth/AuthenticateTest.php new file mode 100644 index 0000000..eec8b76 --- /dev/null +++ b/tests/Auth/AuthenticateTest.php @@ -0,0 +1,364 @@ +assertInstanceOf(Authenticate::class, $auth); + } + + /** + * @covers PsrJwt\Auth\Authenticate::authenticate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Body + * @uses PsrJwt\Parser\Bearer + * @uses PsrJwt\Parser\Query + * @uses PsrJwt\Parser\Cookie + */ + public function testAuthenticateOk() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->build() + ->getToken(); + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getCookieParams') + ->once() + ->andReturn(['foo' => 'bar']); + $request->shouldReceive('getQueryParams') + ->once() + ->andReturn(['jwt' => $token]); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn([]); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn([]); + + $authenticate = new Authenticate('jwt', 'Secret123!456$'); + + $result = $authenticate->authenticate($request); + + $this->assertInstanceOf(Auth::class, $result); + $this->assertSame(200, $result->getCode()); + $this->assertSame('Ok', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::authenticate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Body + * @uses PsrJwt\Parser\Bearer + * @uses PsrJwt\Parser\Query + * @uses PsrJwt\Parser\Cookie + */ + public function testAuthenticateBadRequest() + { + $jwt = Jwt::builder(); + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getCookieParams') + ->once() + ->andReturn(['foo' => 'bar']); + $request->shouldReceive('getQueryParams') + ->once() + ->andReturn(['hello' => 'world']); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn([]); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn([]); + + $auth = new Authenticate('jwt', 'Secret123!456$'); + + $result = $auth->authenticate($request); + + $this->assertSame(400, $result->getCode()); + $this->assertSame('Bad Request: JSON Web Token not set.', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::hasJwt + * @uses PsrJwt\Auth\Authenticate::__construct + */ + public function testAuthenticateHasJwt() + { + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'hasJwt'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, ['abc.abc.abc']); + + $this->assertTrue($result); + } + + /** + * @covers PsrJwt\Auth\Authenticate::hasJwt + * @uses PsrJwt\Auth\Authenticate::__construct + */ + public function testAuthenticateHasJwtEmpty() + { + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'hasJwt'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, ['']); + + $this->assertFalse($result); + } + + /** + * @covers PsrJwt\Auth\Authenticate::getSecret + * @uses PsrJwt\Auth\Authenticate::__construct + */ + public function testGetSecret() + { + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'getSecret'); + $method->setAccessible(true); + $result = $method->invoke($auth); + + $this->assertSame('secret', $result); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + */ + public function testValidate() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->build() + ->getToken(); + + $auth = new Authenticate('jwt', 'Secret123!456$'); + + $method = new ReflectionMethod(Authenticate::class, 'validate'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$token]); + + $this->assertSame(200, $result->getCode()); + $this->assertSame('Ok', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + */ + public function testValidateBadSecret() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->build() + ->getToken(); + + $auth = new Authenticate('jwt', 'Secret'); + + $method = new ReflectionMethod(Authenticate::class, 'validate'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$token]); + + $this->assertSame(401, $result->getCode()); + $this->assertSame('Unauthorized: Signature is invalid.', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + */ + public function testValidateBadExpiration() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('exp', time() - 10) + ->build() + ->getToken(); + + $auth = new Authenticate('jwt', 'Secret123!456$'); + + $method = new ReflectionMethod(Authenticate::class, 'validate'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$token]); + + $this->assertSame(401, $result->getCode()); + $this->assertSame('Unauthorized: Expiration claim has expired.', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validate + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + */ + public function testValidateBadNotBefore() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('nbf', time() + 60) + ->build() + ->getToken(); + + $auth = new Authenticate('jwt', 'Secret123!456$'); + + $method = new ReflectionMethod(Authenticate::class, 'validate'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$token]); + + $this->assertSame(401, $result->getCode()); + $this->assertSame('Unauthorized: Not Before claim has not elapsed.', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validationResponse + * @uses PsrJwt\Auth\Authenticate::__construct + * @uses PsrJwt\Auth\Auth + */ + public function testValidationResponse() + { + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'validationResponse'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [0, 'Ok']); + + $this->assertInstanceOf(Auth::class, $result); + $this->assertSame(200, $result->getCode()); + $this->assertSame('Ok', $result->getMessage()); + } + + /** + * @covers PsrJwt\Auth\Authenticate::validationResponse + * @uses PsrJwt\Auth\Authenticate::__construct + * @uses PsrJwt\Auth\Auth + */ + public function testValidationResponseErrors() + { + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'validationResponse'); + $method->setAccessible(true); + + $errors = [ + [1, 'Error 1'], + [2, 'Error 1'], + [3, 'Error 1'], + [4, 'Error 1'], + [5, 'Error 1'] + ]; + + foreach ($errors as $error) { + $result = $method->invokeArgs($auth, [$error[0], $error[1]]); + + $this->assertInstanceOf(Auth::class, $result); + $this->assertSame(401, $result->getCode()); + $this->assertSame('Unauthorized: ' . $error[1], $result->getMessage()); + } + } + + /** + * @covers PsrJwt\Auth\Authenticate::getToken + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Bearer + */ + public function testGetToken() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn(['Bearer abc.def.ghi']); + + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'getToken'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$request]); + + $this->assertSame('abc.def.ghi', $result); + } + + /** + * @expectedException ReallySimpleJWT\Exception\ValidateException + * @expectedExceptionMessage JSON Web Token not set. + * @expectedExceptionCode 11 + * @covers PsrJwt\Auth\Authenticate::getToken + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Bearer + * @uses PsrJwt\Parser\Body + * @uses PsrJwt\Parser\Cookie + * @uses PsrJwt\Parser\Query + */ + public function testGetTokenNoToken() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn([]); + $request->shouldReceive('getCookieParams') + ->once() + ->andReturn([]); + $request->shouldReceive('getQueryParams') + ->once() + ->andReturn([]); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn([]); + + $auth = new Authenticate('jwt', 'secret'); + + $method = new ReflectionMethod(Authenticate::class, 'getToken'); + $method->setAccessible(true); + $result = $method->invokeArgs($auth, [$request]); + } + + public function tearDown() + { + m::close(); + } +} diff --git a/tests/Factory/JwtAuthTest.php b/tests/Factory/JwtAuthTest.php new file mode 100644 index 0000000..1f0f971 --- /dev/null +++ b/tests/Factory/JwtAuthTest.php @@ -0,0 +1,25 @@ +assertInstanceOf( + JwtAuthMiddleware::class, + JwtAuth::middleware('jwt', '$Secret123!') + ); + } +} diff --git a/tests/Factory/JwtTest.php b/tests/Factory/JwtTest.php new file mode 100644 index 0000000..fce9d19 --- /dev/null +++ b/tests/Factory/JwtTest.php @@ -0,0 +1,27 @@ +assertInstanceOf(Build::class, Jwt::builder()); + } + + /** + * @covers PsrJwt\Factory\Jwt::parser + */ + public function testJwtParser() + { + $this->assertInstanceOf(Parse::class, Jwt::parser('aaa.bbb.ccc', 'secret')); + } +} diff --git a/tests/JwtAuthFactoryTest.php b/tests/JwtAuthFactoryTest.php deleted file mode 100644 index ad5f8ad..0000000 --- a/tests/JwtAuthFactoryTest.php +++ /dev/null @@ -1,48 +0,0 @@ -assertInstanceOf( - JwtAuthMiddleware::class, - JwtAuthFactory::middleware() - ); - } - - /** - * @covers PsrJwt\JwtAuthFactory::invokable - * @uses PsrJwt\JwtAuthHandler::__construct - * @uses PsrJwt\JwtAuthInvokable::__construct - */ - public function testJwtAuthFactoryInvokable() - { - $this->assertInstanceOf( - JwtAuthInvokable::class, - JwtAuthFactory::invokable('jwt', '$Secret123!') - ); - } - - /** - * @covers PsrJwt\JwtAuthFactory::handler - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testJwtAuthFactoryHandler() - { - $this->assertInstanceOf( - JwtAuthHandler::class, - JwtAuthFactory::handler('jwt', '$Secret123!') - ); - } -} diff --git a/tests/JwtAuthHandlerTest.php b/tests/JwtAuthHandlerTest.php deleted file mode 100644 index 2a039c0..0000000 --- a/tests/JwtAuthHandlerTest.php +++ /dev/null @@ -1,264 +0,0 @@ -assertInstanceOf(JwtAuthHandler::class, $handler); - $this->assertInstanceOf(RequestHandlerInterface::class, $handler); - } - - /** - * @covers PsrJwt\JwtAuthHandler::handle - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - * @uses PsrJwt\JwtParse - * @uses PsrJwt\Parser\Body - * @uses PsrJwt\Parser\Bearer - * @uses PsrJwt\Parser\Server - * @uses PsrJwt\Parser\Query - * @uses PsrJwt\Parser\Cookie - */ - public function testJwtAuthHandlerResponse() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->build() - ->getToken(); - - $request = m::mock(ServerRequestInterface::class); - $request->shouldReceive('getServerParams') - ->once() - ->andReturn(['jwt' => $token]); - $request->shouldReceive('getCookieParams') - ->once() - ->andReturn(['foo' => 'bar']); - $request->shouldReceive('getQueryParams') - ->once() - ->andReturn(['hello' => 'world']); - $request->shouldReceive('getParsedBody') - ->twice() - ->andReturn([]); - $request->shouldReceive('getHeader') - ->with('authorization') - ->once() - ->andReturn([]); - - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); - - $result = $handler->handle($request); - - $this->assertInstanceOf(ResponseInterface::class, $result); - } - - /** - * @covers PsrJwt\JwtAuthHandler::hasJwt - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testJwtAuthHandlerHasJwt() - { - $handler = new JwtAuthHandler('jwt', 'secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'hasJwt'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, ['abc.abc.abc']); - - $this->assertTrue($result); - } - - /** - * @covers PsrJwt\JwtAuthHandler::hasJwt - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testJwtAuthHandlerHasJwtEmpty() - { - $handler = new JwtAuthHandler('jwt', 'secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'hasJwt'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, ['']); - - $this->assertFalse($result); - } - - /** - * @covers PsrJwt\JwtAuthHandler::getSecret - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testGetSecret() - { - $handler = new JwtAuthHandler('jwt', 'secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'getSecret'); - $method->setAccessible(true); - $result = $method->invoke($handler); - - $this->assertSame('secret', $result); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validate - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - */ - public function testValidate() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->build() - ->getToken(); - - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validate'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, [$token]); - - $this->assertSame(200, $result->getStatusCode()); - $this->assertSame('Ok', $result->getReasonPhrase()); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validate - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - */ - public function testValidateBadSecret() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->build() - ->getToken(); - - $handler = new JwtAuthHandler('jwt', 'Secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validate'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, [$token]); - - $this->assertSame(401, $result->getStatusCode()); - $this->assertSame('Unauthorized: Signature is invalid.', $result->getReasonPhrase()); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validate - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - */ - public function testValidateBadExpiration() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('exp', time() - 10) - ->build() - ->getToken(); - - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validate'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, [$token]); - - $this->assertSame(401, $result->getStatusCode()); - $this->assertSame('Unauthorized: Expiration claim has expired.', $result->getReasonPhrase()); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validate - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - */ - public function testValidateBadNotBefore() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('nbf', time() + 60) - ->build() - ->getToken(); - - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validate'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, [$token]); - - $this->assertSame(401, $result->getStatusCode()); - $this->assertSame('Unauthorized: Not Before claim has not elapsed.', $result->getReasonPhrase()); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validationResponse - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testValidationResponse() - { - $handler = new JwtAuthHandler('jwt', 'secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validationResponse'); - $method->setAccessible(true); - $result = $method->invokeArgs($handler, [0, 'Ok']); - - $this->assertInstanceOf(ResponseInterface::class, $result); - $this->assertSame(200, $result->getStatusCode()); - $this->assertSame('Ok', $result->getReasonPhrase()); - } - - /** - * @covers PsrJwt\JwtAuthHandler::validationResponse - * @uses PsrJwt\JwtAuthHandler::__construct - */ - public function testValidationResponseErrors() - { - $handler = new JwtAuthHandler('jwt', 'secret'); - - $method = new ReflectionMethod(JwtAuthHandler::class, 'validationResponse'); - $method->setAccessible(true); - - $errors = [ - [1, 'Error 1'], - [2, 'Error 1'], - [3, 'Error 1'], - [4, 'Error 1'], - [5, 'Error 1'] - ]; - - foreach ($errors as $error) { - $result = $method->invokeArgs($handler, [$error[0], $error[1]]); - - $this->assertInstanceOf(ResponseInterface::class, $result); - $this->assertSame(401, $result->getStatusCode()); - $this->assertSame('Unauthorized: ' . $error[1], $result->getReasonPhrase()); - } - } - - public function tearDown() { - m::close(); - } -} diff --git a/tests/JwtAuthInvokableTest.php b/tests/JwtAuthInvokableTest.php deleted file mode 100644 index 3e92c37..0000000 --- a/tests/JwtAuthInvokableTest.php +++ /dev/null @@ -1,122 +0,0 @@ -assertInstanceOf(JwtAuthInvokable::class, $invokable); - } - - /** - * @covers PsrJwt\JwtAuthInvokable::__invoke - * @uses PsrJwt\JwtAuthInvokable::__construct - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - * @uses PsrJwt\JwtParse - * @uses PsrJwt\Parser\Bearer - */ - public function testInvoke() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('nbf', time() - 60) - ->build() - ->getToken(); - - $request = m::mock(ServerRequestInterface::class); - $request->shouldReceive('getHeader') - ->with('authorization') - ->once() - ->andReturn(['Bearer ' . $token]); - - $response = m::mock(ResponseInterface::class); - - $next = function($request, $response) { - return $response; - }; - - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); - - $invokable = new JwtAuthInvokable($handler); - - $result = $invokable($request, $response, $next); - - $this->assertInstanceOf(ResponseInterface::class, $result); - } - - /** - * @covers PsrJwt\JwtAuthInvokable::__invoke - * @uses PsrJwt\JwtAuthInvokable - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtValidate - * @uses PsrJwt\JwtParse - * @uses PsrJwt\Parser\Body - * @uses PsrJwt\Parser\Bearer - * @uses PsrJwt\Parser\Server - * @uses PsrJwt\Parser\Query - * @uses PsrJwt\Parser\Cookie - */ - public function testInvokeFail() - { - $request = m::mock(ServerRequestInterface::class); - $request->shouldReceive('getServerParams') - ->once() - ->andReturn(['jwt' => 'abc.abc.abc']); - $request->shouldReceive('getCookieParams') - ->once() - ->andReturn(['hello' => 'world']); - $request->shouldReceive('getQueryParams') - ->once() - ->andReturn(['car' => 'park']); - $request->shouldReceive('getParsedBody') - ->twice() - ->andReturn(['gary' => 'barlow']); - $request->shouldReceive('getHeader') - ->with('authorization') - ->once() - ->andReturn([]); - - $response = m::mock(ResponseInterface::class); - - $next = function($request, $response) { - return $response; - }; - - $handler = new JwtAuthHandler('jwt', 'secret'); - - $invokable = new JwtAuthInvokable($handler); - - $result = $invokable($request, $response, $next); - - $this->assertSame(401, $result->getStatusCode()); - $this->assertSame('Unauthorized: Signature is invalid.', $result->getReasonPhrase()); - } - - public function tearDown() { - m::close(); - } -} diff --git a/tests/JwtAuthMiddlewareTest.php b/tests/JwtAuthMiddlewareTest.php index 09c1a7d..75a7867 100644 --- a/tests/JwtAuthMiddlewareTest.php +++ b/tests/JwtAuthMiddlewareTest.php @@ -3,23 +3,29 @@ namespace Tests; use PHPUnit\Framework\TestCase; -use PsrJwt\JwtFactory; +use Nyholm\Psr7\Factory\Psr17Factory; +use PsrJwt\Factory\Jwt; use PsrJwt\JwtAuthMiddleware; -use PsrJwt\JwtAuthHandler; +use PsrJwt\Auth\Authenticate; +use PsrJwt\Auth\Auth; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\MiddlewareInterface; use Mockery as m; +use ReflectionMethod; class JwtAuthMiddlewareTest extends TestCase { /** * @covers PsrJwt\JwtAuthMiddleware + * @uses PsrJwt\Auth\Authenticate */ public function testJwtAuthProcess() { - $process = new JwtAuthMiddleware('jwt', 'secret'); + $authenticate = new Authenticate('jwt', 'secret'); + + $process = new JwtAuthMiddleware($authenticate); $this->assertInstanceOf(JwtAuthMiddleware::class, $process); $this->assertInstanceOf(MiddlewareInterface::class, $process); @@ -27,15 +33,17 @@ public function testJwtAuthProcess() /** * @covers PsrJwt\JwtAuthMiddleware::process - * @uses PsrJwt\JwtFactory - * @uses PsrJwt\JwtAuthHandler - * @uses PsrJwt\JwtParse - * @uses PsrJwt\JwtValidate + * @uses PsrJwt\JwtAuthMiddleware::__construct + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Validation\Validate * @uses PsrJwt\Parser\Bearer */ public function testProcess() { - $jwt = JwtFactory::builder(); + $jwt = Jwt::builder(); $token = $jwt->setSecret('Secret123!456$') ->setIssuer('localhost') ->setPayloadClaim('nbf', time() - 60) @@ -48,16 +56,178 @@ public function testProcess() ->once() ->andReturn(['Bearer ' . $token]); - $handler = new JwtAuthHandler('jwt', 'Secret123!456$'); + $response = new Psr17Factory(); + $response = $response->createResponse(200, 'Ok'); + + $handler = m::mock(RequestHandlerInterface::class); + $handler->shouldReceive('handle') + ->once() + ->andReturn($response); + + $authenticate = new Authenticate('jwt', 'Secret123!456$'); + + $process = new JwtAuthMiddleware($authenticate); + + $result = $process->process($request, $handler); + + $this->assertInstanceOf(ResponseInterface::class, $result); + $this->assertSame(200, $result->getStatusCode()); + $this->assertSame('Ok', $result->getReasonPhrase()); + } + + /** + * @covers PsrJwt\JwtAuthMiddleware::process + * @uses PsrJwt\JwtAuthMiddleware + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Parser\Bearer + * @uses PsrJwt\Parser\Body + * @uses PsrJwt\Parser\Cookie + * @uses PsrJwt\Parser\Query + */ + public function testProcessFail() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getCookieParams') + ->once() + ->andReturn(['car' => 'park']); + $request->shouldReceive('getQueryParams') + ->once() + ->andReturn(['farm' => 'yard']); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn(['gary' => 'barlow']); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn([]); + + $handler = m::mock(RequestHandlerInterface::class); + + $authenticate = new Authenticate('jwt', 'Secret123!456$'); - $process = new JwtAuthMiddleware(); + $process = new JwtAuthMiddleware($authenticate); $result = $process->process($request, $handler); $this->assertInstanceOf(ResponseInterface::class, $result); + $this->assertSame(400, $result->getStatusCode()); + $this->assertSame('Bad Request: JSON Web Token not set.', $result->getReasonPhrase()); + } + + /** + * @covers PsrJwt\JwtAuthMiddleware::__invoke + * @uses PsrJwt\JwtAuthMiddleware::__construct + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Bearer + */ + public function testInvoke() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('nbf', time() - 60) + ->build() + ->getToken(); + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn(['Bearer ' . $token]); + + $response = m::mock(ResponseInterface::class); + + $next = function ($request, $response) { + return $response; + }; + + $auth = new Authenticate('jwt', 'Secret123!456$'); + + $invokable = new JwtAuthMiddleware($auth); + + $result = $invokable($request, $response, $next); + + $this->assertInstanceOf(ResponseInterface::class, $result); + } + + /** + * @covers PsrJwt\JwtAuthMiddleware::__invoke + * @uses PsrJwt\JwtAuthMiddleware + * @uses PsrJwt\Auth\Authenticate + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Factory\Jwt + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Body + * @uses PsrJwt\Parser\Bearer + * @uses PsrJwt\Parser\Query + * @uses PsrJwt\Parser\Cookie + */ + public function testInvokeFail() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getCookieParams') + ->once() + ->andReturn(['car' => 'park']); + $request->shouldReceive('getQueryParams') + ->once() + ->andReturn(['jwt' => 'abc.abc.abc']); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn(['gary' => 'barlow']); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn([]); + + $response = m::mock(ResponseInterface::class); + + $next = function ($request, $response) { + return $response; + }; + + $auth = new Authenticate('jwt', 'secret'); + + $invokable = new JwtAuthMiddleware($auth); + + $result = $invokable($request, $response, $next); + + $this->assertSame(401, $result->getStatusCode()); + $this->assertSame('Unauthorized: Signature is invalid.', $result->getReasonPhrase()); + } + + /** + * @covers PsrJwt\JwtAuthMiddleware::failResponse + * @uses PsrJwt\JwtAuthMiddleware + * @uses PsrJwt\Auth\Auth + * @uses PsrJwt\Auth\Authenticate + */ + public function testFailResponse() + { + $authenticate = new Authenticate('jwt', 'secret'); + $auth = new Auth(400, 'Bad Request'); + + $middleware = new JwtAuthMiddleware($authenticate); + + $method = new ReflectionMethod(JwtAuthMiddleware::class, 'failResponse'); + $method->setAccessible(true); + $result = $method->invokeArgs($middleware, [$auth]); + + $this->assertInstanceOf(ResponseInterface::class, $result); + $this->assertSame(400, $result->getStatusCode()); + $this->assertSame('Bad Request', $result->getReasonPhrase()); } - public function tearDown() { + public function tearDown() + { m::close(); } } diff --git a/tests/JwtFactoryTest.php b/tests/JwtFactoryTest.php deleted file mode 100644 index d315487..0000000 --- a/tests/JwtFactoryTest.php +++ /dev/null @@ -1,27 +0,0 @@ -assertInstanceOf(Build::class, JwtFactory::builder()); - } - - /** - * @covers PsrJwt\JwtFactory::parser - */ - public function testJwtFactoryParser() - { - $this->assertInstanceOf(Parse::class, JwtFactory::parser('aaa.bbb.ccc', 'secret')); - } -} diff --git a/tests/JwtParseTest.php b/tests/JwtParseTest.php deleted file mode 100644 index 0afb861..0000000 --- a/tests/JwtParseTest.php +++ /dev/null @@ -1,48 +0,0 @@ - 'jwt']); - $this->assertInstanceOf(JwtParse::class, $parse); - } - - /** - * @covers PsrJwt\JwtParse::findToken - * @uses PsrJwt\JwtParse - * @uses PsrJwt\Parser\Bearer - */ - public function testFindToken() - { - $request = m::mock(ServerRequestInterface::class); - $request->shouldReceive('getHeader') - ->with('authorization') - ->once() - ->andReturn(['Bearer abc.def.ghi']); - - $parse = new JwtParse(['token_key' => 'jwt']); - $parse->addParser(Bearer::class); - - $result = $parse->findToken($request); - - $this->assertSame('abc.def.ghi', $result); - } - - public function tearDown() { - m::close(); - } -} diff --git a/tests/JwtValidateTest.php b/tests/JwtValidateTest.php deleted file mode 100644 index da88602..0000000 --- a/tests/JwtValidateTest.php +++ /dev/null @@ -1,81 +0,0 @@ -setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('exp', time() - 10) - ->build() - ->getToken(); - - $validate = new JwtValidate( - JwtFactory::parser($token, 'Secret123!456$') - ); - - $this->assertInstanceOf(JwtValidate::class, $validate); - } - - /** - * @covers PsrJwt\JwtValidate::validate - * @uses PsrJwt\JwtValidate - * @uses PsrJwt\JwtFactory - */ - public function testValidate() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('exp', time() - 10) - ->build() - ->getToken(); - - $validate = new JwtValidate( - JwtFactory::parser($token, 'Secret123!456$') - ); - - $result = $validate->validate(); - - $this->assertSame(4, $result['code']); - $this->assertSame('Expiration claim has expired.', $result['message']); - } - - /** - * @covers PsrJwt\JwtValidate::validateNotBefore - * @uses PsrJwt\JwtValidate - * @uses PsrJwt\JwtFactory - */ - public function testValidateNotBefore() - { - $jwt = JwtFactory::builder(); - $token = $jwt->setSecret('Secret123!456$') - ->setIssuer('localhost') - ->setPayloadClaim('nbf', time() + 10) - ->build() - ->getToken(); - - $validate = new JwtValidate( - JwtFactory::parser($token, 'Secret123!456$') - ); - - $result = $validate->validateNotBefore( - ['code' => 0, 'message' => 'Ok'] - ); - - $this->assertSame(5, $result['code']); - $this->assertSame('Not Before claim has not elapsed.', $result['message']); - } -} diff --git a/tests/Parser/BearerTest.php b/tests/Parser/BearerTest.php index d593b36..93d3150 100644 --- a/tests/Parser/BearerTest.php +++ b/tests/Parser/BearerTest.php @@ -1,6 +1,6 @@ assertSame('abc.def.ghi', $result); } + /** + * @covers PsrJwt\Parser\Body::parse + * @uses PsrJwt\Parser\Body + */ + public function testParseObject() + { + $object = new \stdClass(); + $object->jwt = 'abc.def.ghi'; + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn($object); + + $body = new Body(['token_key' => 'jwt']); + $result = $body->parse($request); + + $this->assertSame('abc.def.ghi', $result); + } + + /** + * @covers PsrJwt\Parser\Body::parse + * @uses PsrJwt\Parser\Body + */ + public function testParseString() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody') + ->twice() + ->andReturn('hello'); + + $body = new Body(['token_key' => 'jwt']); + $result = $body->parse($request); + + $this->assertSame('', $result); + } + + /** + * @covers PsrJwt\Parser\Body::parseBodyObject + * @uses PsrJwt\Parser\Body::__construct + */ + public function testParseBodyObject() + { + $object = new \stdClass(); + $object->jwt = 'abc.def.ghi'; + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody') + ->once() + ->andReturn($object); + + $body = new Body(['token_key' => 'jwt']); + + $method = new ReflectionMethod(Body::class, 'parseBodyObject'); + $method->setAccessible(true); + $result = $method->invokeArgs($body, [$request]); + + $this->assertSame('abc.def.ghi', $result); + } + + /** + * @covers PsrJwt\Parser\Body::parseBodyObject + * @uses PsrJwt\Parser\Body::__construct + */ + public function testParseBodyObjectNoKey() + { + $object = new \stdClass(); + + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody') + ->once() + ->andReturn($object); + + $body = new Body(['token_key' => 'jwt']); + + $method = new ReflectionMethod(Body::class, 'parseBodyObject'); + $method->setAccessible(true); + $result = $method->invokeArgs($body, [$request]); + + $this->assertSame('', $result); + } + + /** + * @covers PsrJwt\Parser\Body::parseBodyObject + * @uses PsrJwt\Parser\Body::__construct + */ + public function testParseBodyObjectNoObject() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody') + ->once() + ->andReturn([]); + + $body = new Body(['token_key' => 'jwt']); + + $method = new ReflectionMethod(Body::class, 'parseBodyObject'); + $method->setAccessible(true); + $result = $method->invokeArgs($body, [$request]); + + $this->assertSame('', $result); + } + public function tearDown() { m::close(); diff --git a/tests/Parser/CookieTest.php b/tests/Parser/CookieTest.php index 679a414..89d2916 100644 --- a/tests/Parser/CookieTest.php +++ b/tests/Parser/CookieTest.php @@ -1,6 +1,6 @@ 'jwt']); + $this->assertInstanceOf(Parse::class, $parse); + } + + /** + * @covers PsrJwt\Parser\Parse::findToken + * @uses PsrJwt\Parser\Parse + * @uses PsrJwt\Parser\Bearer + */ + public function testFindToken() + { + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getHeader') + ->with('authorization') + ->once() + ->andReturn(['Bearer abc.def.ghi']); + + $parse = new Parse(['token_key' => 'jwt']); + $parse->addParser(Bearer::class); + + $result = $parse->findToken($request); + + $this->assertSame('abc.def.ghi', $result); + } + + /** + * @covers PsrJwt\Parser\Parse::addParser + * @covers PsrJwt\Parser\Parse::getParsers + * @uses PsrJwt\Parser\Parse + */ + public function testAddParser() + { + $parse = new Parse(['token_key' => 'jwt']); + $parse->addParser(Bearer::class); + $parse->addParser(Cookie::class); + + $result = $parse->getParsers(); + + $this->assertCount(2, $result); + $this->assertSame(Bearer::class, $result[0]); + $this->assertSame(Cookie::class, $result[1]); + } + + /** + * @covers PsrJwt\Parser\Parse::findToken + * @uses PsrJwt\Parser\Parse + */ + public function testFindTokenFail() + { + $request = m::mock(ServerRequestInterface::class); + + $parse = new Parse(['token_key' => 'jwt']); + $result = $parse->findToken($request); + + $this->assertEmpty($result); + } + + public function tearDown() + { + m::close(); + } +} diff --git a/tests/Parser/QueryTest.php b/tests/Parser/QueryTest.php index e319fef..b5120a4 100644 --- a/tests/Parser/QueryTest.php +++ b/tests/Parser/QueryTest.php @@ -1,6 +1,6 @@ 'jwt']); - - $this->assertInstanceOf(Server::class, $server); - $this->assertInstanceOf(ParserInterface::class, $server); - } - - /** - * @covers PsrJwt\Parser\Server::parse - * @uses PsrJwt\Parser\Server::__construct - */ - public function testParse() - { - $request = m::mock(ServerRequestInterface::class); - $request->shouldReceive('getserverParams') - ->once() - ->andReturn(['jwt' => 'abc.def.ghi']); - - $server = new Server(['token_key' => 'jwt']); - $result = $server->parse($request); - - $this->assertSame('abc.def.ghi', $result); - } - - public function tearDown() - { - m::close(); - } -} diff --git a/tests/Validation/ValidateTest.php b/tests/Validation/ValidateTest.php new file mode 100644 index 0000000..5e5e8a4 --- /dev/null +++ b/tests/Validation/ValidateTest.php @@ -0,0 +1,131 @@ +setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('exp', time() - 10) + ->build() + ->getToken(); + + $validate = new Validate( + Jwt::parser($token, 'Secret123!456$') + ); + + $this->assertInstanceOf(Validate::class, $validate); + } + + /** + * @covers PsrJwt\Validation\Validate::validate + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Factory\Jwt + */ + public function testValidateOk() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('exp', time() + 10) + ->build() + ->getToken(); + + $validate = new Validate( + Jwt::parser($token, 'Secret123!456$') + ); + + $result = $validate->validate(); + + $this->assertSame(0, $result['code']); + $this->assertSame('Ok', $result['message']); + } + + /** + * @covers PsrJwt\Validation\Validate::validate + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Factory\Jwt + */ + public function testValidateExpiration() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('exp', time() - 10) + ->build() + ->getToken(); + + $validate = new Validate( + Jwt::parser($token, 'Secret123!456$') + ); + + $result = $validate->validate(); + + $this->assertSame(4, $result['code']); + $this->assertSame('Expiration claim has expired.', $result['message']); + } + + /** + * @covers PsrJwt\Validation\Validate::validateNotBefore + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Factory\Jwt + */ + public function testValidateNotBefore() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('nbf', time() + 10) + ->build() + ->getToken(); + + $validate = new Validate( + Jwt::parser($token, 'Secret123!456$') + ); + + $result = $validate->validateNotBefore( + ['code' => 0, 'message' => 'Ok'] + ); + + $this->assertSame(5, $result['code']); + $this->assertSame('Not Before claim has not elapsed.', $result['message']); + } + + /** + * @covers PsrJwt\Validation\Validate::validateNotBefore + * @uses PsrJwt\Validation\Validate + * @uses PsrJwt\Factory\Jwt + */ + public function testValidateNotBeforeOk() + { + $jwt = Jwt::builder(); + $token = $jwt->setSecret('Secret123!456$') + ->setIssuer('localhost') + ->setPayloadClaim('nbf', time() - 20) + ->build() + ->getToken(); + + $validate = new Validate( + Jwt::parser($token, 'Secret123!456$') + ); + + $result = $validate->validateNotBefore( + ['code' => 0, 'message' => 'Ok'] + ); + + $this->assertSame(0, $result['code']); + $this->assertSame('Ok', $result['message']); + } +}