diff --git a/composer.json b/composer.json index d7d20d44d..c3316f2c5 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "minimum-stability": "dev", diff --git a/src/Bridge/AccessTokenRepository.php b/src/Bridge/AccessTokenRepository.php index e3a8e7559..16b4da617 100644 --- a/src/Bridge/AccessTokenRepository.php +++ b/src/Bridge/AccessTokenRepository.php @@ -3,7 +3,7 @@ namespace Laravel\Passport\Bridge; use DateTime; -use Illuminate\Database\Connection; +use Laravel\Passport\TokenRepository; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -17,7 +17,7 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface * * @var \Illuminate\Database\Connection */ - protected $database; + protected $tokenRepository; /** * Create a new repository instance. @@ -25,9 +25,9 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface * @param \Illuminate\Database\Connection $database * @return void */ - public function __construct(Connection $database) + public function __construct(TokenRepository $tokenRepository) { - $this->database = $database; + $this->tokenRepository = $tokenRepository; } /** @@ -43,7 +43,7 @@ public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity) { - $this->database->table('oauth_access_tokens')->insert([ + $this->tokenRepository->create([ 'id' => $accessTokenEntity->getIdentifier(), 'user_id' => $accessTokenEntity->getUserIdentifier(), 'client_id' => $accessTokenEntity->getClient()->getIdentifier(), @@ -60,8 +60,7 @@ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEnt */ public function revokeAccessToken($tokenId) { - $this->database->table('oauth_access_tokens') - ->where('id', $tokenId)->update(['revoked' => true]); + $this->tokenRepository->revokeAccessToken($tokenId); } /** @@ -69,7 +68,6 @@ public function revokeAccessToken($tokenId) */ public function isAccessTokenRevoked($tokenId) { - return $this->database->table('oauth_access_tokens') - ->where('id', $tokenId)->where('revoked', 1)->exists(); + return $this->tokenRepository->isAccessTokenRevoked($tokenId); } } diff --git a/src/Http/Middleware/CheckClientCredentials.php b/src/Http/Middleware/CheckClientCredentials.php index f31d3bfed..80ad671ba 100644 --- a/src/Http/Middleware/CheckClientCredentials.php +++ b/src/Http/Middleware/CheckClientCredentials.php @@ -37,16 +37,22 @@ public function __construct(ResourceServer $server) * * @throws \Illuminate\Auth\AuthenticationException */ - public function handle($request, Closure $next) + public function handle($request, Closure $next, ...$scopes) { $psr = (new DiactorosFactory)->createRequest($request); try{ - $this->server->validateAuthenticatedRequest($psr); + $psr = $this->server->validateAuthenticatedRequest($psr); } catch (OAuthServerException $e) { throw new AuthenticationException; } + foreach ($scopes as $scope) { + if (!in_array($scope,$psr->getAttribute('oauth_scopes'))) { + throw new AuthenticationException; + } + } + return $next($request); } } diff --git a/src/TokenRepository.php b/src/TokenRepository.php index 244abda9c..26e624244 100644 --- a/src/TokenRepository.php +++ b/src/TokenRepository.php @@ -4,6 +4,17 @@ class TokenRepository { + /** + * Creates a new Access Token + * + * @param array $attributes + * @return Token + */ + public function create($attributes) + { + return Token::create($attributes); + } + /** * Get a token by the given ID. * @@ -21,11 +32,33 @@ public function find($id) * @param Token $token * @return void */ - public function save($token) + public function save(Token $token) { $token->save(); } + /** + * Revoke an access token. + * + * @param string $id + */ + public function revokeAccessToken($id) + { + return $this->find($id)->update(['revoked' => true]); + } + + /** + * Check if the access token has been revoked. + * + * @param string $id + * + * @return bool Return true if this token has been revoked + */ + public function isAccessTokenRevoked($id) + { + return Token::where('id', $id)->where('revoked', true)->exists(); + } + /** * Revoke all of the access tokens for a given user and client. * diff --git a/tests/BridgeAccessTokenRepositoryTest.php b/tests/BridgeAccessTokenRepositoryTest.php index 5cd5f0004..1562e46dd 100644 --- a/tests/BridgeAccessTokenRepositoryTest.php +++ b/tests/BridgeAccessTokenRepositoryTest.php @@ -13,9 +13,9 @@ public function test_access_tokens_can_be_persisted() { $expiration = Carbon::now(); - $database = Mockery::mock('Illuminate\Database\Connection'); + $tokenRepository = Mockery::mock('Laravel\Passport\TokenRepository'); - $database->shouldReceive('table->insert')->once()->andReturnUsing(function ($array) use ($expiration) { + $tokenRepository->shouldReceive('create')->once()->andReturnUsing(function ($array) use ($expiration) { $this->assertEquals(1, $array['id']); $this->assertEquals(2, $array['user_id']); $this->assertEquals('client-id', $array['client_id']); @@ -31,7 +31,7 @@ public function test_access_tokens_can_be_persisted() $accessToken->setExpiryDateTime($expiration); $accessToken->setClient(new Laravel\Passport\Bridge\Client('client-id', 'name', 'redirect')); - $repository = new Laravel\Passport\Bridge\AccessTokenRepository($database); + $repository = new Laravel\Passport\Bridge\AccessTokenRepository($tokenRepository); $repository->persistNewAccessToken($accessToken); } diff --git a/tests/CheckClientCredentialsTest.php b/tests/CheckClientCredentialsTest.php new file mode 100644 index 000000000..44861e0cb --- /dev/null +++ b/tests/CheckClientCredentialsTest.php @@ -0,0 +1,78 @@ +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'); + + $middleware = new CheckClientCredentials($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $response = $middleware->handle($request, function () { + return 'response'; + }); + + $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')->andReturnUsing(function () { + throw new League\OAuth2\Server\Exception\OAuthServerException('message', 500, 'error type'); + }); + + $middleware = new CheckClientCredentials($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $middleware->handle($request, function () { + return 'response'; + }); + + } + + /** + * @expectedException Illuminate\Auth\AuthenticationException + */ + public function test_exception_is_thrown_if_token_does_not_have_required_scopes() + { + $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','notbar']); + + $middleware = new CheckClientCredentials($resourceServer); + + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $response = $middleware->handle($request, function () { + return 'response'; + },'foo', 'bar'); + + } + +} diff --git a/tests/PersonalAccessTokenFactoryTest.php b/tests/PersonalAccessTokenFactoryTest.php index ef4c1ed39..09c5d5c45 100644 --- a/tests/PersonalAccessTokenFactoryTest.php +++ b/tests/PersonalAccessTokenFactoryTest.php @@ -39,7 +39,7 @@ class PersonalAccessTokenFactoryTestClientStub public $secret = 'something'; } -class PersonalAccessTokenFactoryTestModelStub extends Illuminate\Database\Eloquent\Model +class PersonalAccessTokenFactoryTestModelStub extends Laravel\Passport\Token { public $id = 1; public $secret = 'something';