From 58d02a84c8e214e0c279bcd7c6fb8ea89ed2fb48 Mon Sep 17 00:00:00 2001 From: vitorbari Date: Thu, 25 Oct 2018 08:13:51 -0300 Subject: [PATCH] Add middleware CheckClientCredentialsForAnyScope --- .../CheckClientCredentialsForAnyScope.php | 80 +++++++++++++++ .../CheckClientCredentialsForAnyScopeTest.php | 97 +++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 src/Http/Middleware/CheckClientCredentialsForAnyScope.php create mode 100644 tests/CheckClientCredentialsForAnyScopeTest.php diff --git a/src/Http/Middleware/CheckClientCredentialsForAnyScope.php b/src/Http/Middleware/CheckClientCredentialsForAnyScope.php new file mode 100644 index 000000000..67dd7140e --- /dev/null +++ b/src/Http/Middleware/CheckClientCredentialsForAnyScope.php @@ -0,0 +1,80 @@ +server = $server; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param mixed ...$scopes + * @return mixed + * @throws \Illuminate\Auth\AuthenticationException + */ + public function handle($request, Closure $next, ...$scopes) + { + $psr = (new DiactorosFactory)->createRequest($request); + + try { + $psr = $this->server->validateAuthenticatedRequest($psr); + } catch (OAuthServerException $e) { + throw new AuthenticationException; + } + + if ($this->validateScopes($psr, $scopes)) { + return $next($request); + } + + throw new MissingScopeException($scopes); + } + + /** + * Validate the scopes on the incoming request. + * + * @param \Psr\Http\Message\ResponseInterface $psr + * @param array $scopes + * @return bool + * @throws \Laravel\Passport\Exceptions\MissingScopeException + */ + protected function validateScopes($psr, $scopes) + { + if (in_array('*', $tokenScopes = $psr->getAttribute('oauth_scopes'))) { + return true; + } + + foreach ($scopes as $scope) { + if (in_array($scope, $tokenScopes)) { + return true; + } + } + + return false; + } +} diff --git a/tests/CheckClientCredentialsForAnyScopeTest.php b/tests/CheckClientCredentialsForAnyScopeTest.php new file mode 100644 index 000000000..a53df7a05 --- /dev/null +++ b/tests/CheckClientCredentialsForAnyScopeTest.php @@ -0,0 +1,97 @@ +shouldReceive('validateAuthenticatedRequest')->andReturn($psr = Mockery::mock()); + $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_access_token_id')->andReturn('token'); + $psr->shouldReceive('getAttribute')->with('oauth_scopes')->andReturn(['*']); + + $middleware = new CheckClientCredentialsForAnyScope($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $response = $middleware->handle($request, function () { + return 'response'; + }); + + $this->assertEquals('response', $response); + } + + public function test_request_is_passed_along_if_token_has_any_required_scope() + { + $resourceServer = Mockery::mock('League\OAuth2\Server\ResourceServer'); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = Mockery::mock()); + $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_access_token_id')->andReturn('token'); + $psr->shouldReceive('getAttribute')->with('oauth_scopes')->andReturn(['foo', 'bar', 'baz']); + + $middleware = new CheckClientCredentialsForAnyScope($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $response = $middleware->handle($request, function () { + return 'response'; + }, 'notfoo', 'bar', 'notbaz'); + + $this->assertEquals('response', $response); + } + + /** + * @expectedException Illuminate\Auth\AuthenticationException + */ + public function test_exception_is_thrown_when_oauth_throws_exception() + { + $resourceServer = Mockery::mock('League\OAuth2\Server\ResourceServer'); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andThrow( + new League\OAuth2\Server\Exception\OAuthServerException('message', 500, 'error type') + ); + + $middleware = new CheckClientCredentialsForAnyScope($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $middleware->handle($request, function () { + return 'response'; + }); + } + + /** + * @expectedException \Laravel\Passport\Exceptions\MissingScopeException + */ + public function test_exception_is_thrown_if_token_does_not_have_required_scope() + { + $resourceServer = Mockery::mock('League\OAuth2\Server\ResourceServer'); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = Mockery::mock()); + $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_access_token_id')->andReturn('token'); + $psr->shouldReceive('getAttribute')->with('oauth_scopes')->andReturn(['foo', 'bar']); + + $middleware = new CheckClientCredentialsForAnyScope($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $response = $middleware->handle($request, function () { + return 'response'; + }, 'baz', 'notbar'); + } +}