diff --git a/database/factories/ClientFactory.php b/database/factories/ClientFactory.php index b34a6c0e..ac345080 100644 --- a/database/factories/ClientFactory.php +++ b/database/factories/ClientFactory.php @@ -40,7 +40,7 @@ public function definition() } /** - * Use as Password Client. + * Use as a Password client. * * @return $this */ @@ -53,7 +53,20 @@ public function asPasswordClient() } /** - * Use as Client Credentials. + * Use as a Personal Access Token client. + * + * @return $this + */ + public function asPersonalAccessTokenClient() + { + return $this->state([ + 'personal_access_client' => true, + 'password_client' => false, + ]); + } + + /** + * Use as a Client Credentials client. * * @return $this */ diff --git a/src/Http/Controllers/AccessTokenController.php b/src/Http/Controllers/AccessTokenController.php index 7c3b395b..e9e57293 100644 --- a/src/Http/Controllers/AccessTokenController.php +++ b/src/Http/Controllers/AccessTokenController.php @@ -2,8 +2,8 @@ namespace Laravel\Passport\Http\Controllers; -use Laravel\Passport\TokenRepository; use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\Exception\OAuthServerException; use Nyholm\Psr7\Response as Psr7Response; use Psr\Http\Message\ServerRequestInterface; @@ -18,25 +18,15 @@ class AccessTokenController */ protected $server; - /** - * The token repository instance. - * - * @var \Laravel\Passport\TokenRepository - */ - protected $tokens; - /** * Create a new controller instance. * * @param \League\OAuth2\Server\AuthorizationServer $server - * @param \Laravel\Passport\TokenRepository $tokens * @return void */ - public function __construct(AuthorizationServer $server, - TokenRepository $tokens) + public function __construct(AuthorizationServer $server) { $this->server = $server; - $this->tokens = $tokens; } /** @@ -48,6 +38,11 @@ public function __construct(AuthorizationServer $server, public function issueToken(ServerRequestInterface $request) { return $this->withErrorHandling(function () use ($request) { + if (array_key_exists('grant_type', $attributes = (array) $request->getParsedBody()) + && $attributes['grant_type'] === 'personal_access') { + throw OAuthServerException::unsupportedGrantType(); + } + return $this->convertResponse( $this->server->respondToAccessTokenRequest($request, new Psr7Response) ); diff --git a/tests/Feature/AccessTokenControllerTest.php b/tests/Feature/AccessTokenControllerTest.php index b39cf7cc..4e519bce 100644 --- a/tests/Feature/AccessTokenControllerTest.php +++ b/tests/Feature/AccessTokenControllerTest.php @@ -269,6 +269,49 @@ public function testGettingCustomResponseType() $this->assertArrayHasKey('id_token', $decodedResponse); $this->assertSame('foo_bar_open_id_token', $decodedResponse['id_token']); } + + public function testPersonalAccessTokenRequestIsDisabled() + { + $user = UserFactory::new()->create([ + 'email' => 'foo@gmail.com', + 'password' => $this->app->make(Hasher::class)->make('foobar123'), + ]); + + /** @var Client $client */ + $client = ClientFactory::new()->asPersonalAccessTokenClient()->create(); + + config([ + 'passport.personal_access_client.id' => $client->getKey(), + 'passport.personal_access_client.secret' => $client->plainSecret, + ]); + + $response = $this->post( + '/oauth/token', + [ + 'grant_type' => 'personal_access', + 'client_id' => $client->getKey(), + 'client_secret' => $client->plainSecret, + 'user_id' => $user->getKey(), + 'scope' => '', + ] + ); + + $response->assertStatus(400); + + $decodedResponse = $response->decodeResponseJson()->json(); + + $this->assertArrayNotHasKey('token_type', $decodedResponse); + $this->assertArrayNotHasKey('expires_in', $decodedResponse); + $this->assertArrayNotHasKey('access_token', $decodedResponse); + + $this->assertArrayHasKey('error', $decodedResponse); + $this->assertSame('unsupported_grant_type', $decodedResponse['error']); + $this->assertArrayHasKey('error_description', $decodedResponse); + + $token = $user->createToken('test'); + + $this->assertInstanceOf(\Laravel\Passport\PersonalAccessTokenResult::class, $token); + } } class IdTokenResponse extends \League\OAuth2\Server\ResponseTypes\BearerTokenResponse diff --git a/tests/Unit/AccessTokenControllerTest.php b/tests/Unit/AccessTokenControllerTest.php index bcd72cb5..4efd11a3 100644 --- a/tests/Unit/AccessTokenControllerTest.php +++ b/tests/Unit/AccessTokenControllerTest.php @@ -4,7 +4,6 @@ use Laravel\Passport\Exceptions\OAuthServerException; use Laravel\Passport\Http\Controllers\AccessTokenController; -use Laravel\Passport\TokenRepository; use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException as LeagueException; use Mockery as m; @@ -23,8 +22,9 @@ protected function tearDown(): void public function test_a_token_can_be_issued() { $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody')->once()->andReturn([]); + $response = m::type(ResponseInterface::class); - $tokens = m::mock(TokenRepository::class); $psrResponse = new Response(); $psrResponse->getBody()->write(json_encode(['access_token' => 'access-token'])); @@ -34,25 +34,26 @@ public function test_a_token_can_be_issued() ->with($request, $response) ->andReturn($psrResponse); - $controller = new AccessTokenController($server, $tokens); + $controller = new AccessTokenController($server); $this->assertSame('{"access_token":"access-token"}', $controller->issueToken($request)->getContent()); } public function test_exceptions_are_handled() { - $tokens = m::mock(TokenRepository::class); + $request = m::mock(ServerRequestInterface::class); + $request->shouldReceive('getParsedBody')->once()->andReturn([]); $server = m::mock(AuthorizationServer::class); $server->shouldReceive('respondToAccessTokenRequest')->with( - m::type(ServerRequestInterface::class), m::type(ResponseInterface::class) + $request, m::type(ResponseInterface::class) )->andThrow(LeagueException::invalidCredentials()); - $controller = new AccessTokenController($server, $tokens); + $controller = new AccessTokenController($server); $this->expectException(OAuthServerException::class); - $controller->issueToken(m::mock(ServerRequestInterface::class)); + $controller->issueToken($request); } }