/**
  * {@inheritDoc}
  */
 public function createTokenResponse(ServerRequestInterface $request, Client $client = null, TokenOwnerInterface $owner = null) : ResponseInterface
 {
     $postParams = $request->getParsedBody();
     $refreshToken = $postParams['refresh_token'] ?? null;
     if (null === $refreshToken) {
         throw OAuth2Exception::invalidRequest('Refresh token is missing');
     }
     // We can fetch the actual token, and validate it
     /** @var RefreshToken $refreshToken */
     $refreshToken = $this->refreshTokenService->getToken((string) $refreshToken);
     if (null === $refreshToken || $refreshToken->isExpired()) {
         throw OAuth2Exception::invalidGrant('Refresh token is expired');
     }
     // We can now create a new access token! First, we need to make some checks on the asked scopes,
     // because according to the spec, a refresh token can create an access token with an equal or lesser
     // scope, but not more
     $scopes = $postParams['scope'] ?? $refreshToken->getScopes();
     if (!$refreshToken->matchScopes($scopes)) {
         throw OAuth2Exception::invalidScope('The scope of the new access token exceeds the scope(s) of the refresh token');
     }
     $owner = $refreshToken->getOwner();
     $accessToken = $this->accessTokenService->createToken($owner, $client, $scopes);
     // We may want to revoke the old refresh token
     if ($this->serverOptions->getRotateRefreshTokens()) {
         if ($this->serverOptions->getRevokeRotatedRefreshTokens()) {
             $this->refreshTokenService->deleteToken($refreshToken);
         }
         $refreshToken = $this->refreshTokenService->createToken($owner, $client, $scopes);
     }
     // We can generate the response!
     return $this->prepareTokenResponse($accessToken, $refreshToken, true);
 }
 /**
  * @dataProvider grantOptions
  */
 public function testCanCreateTokenResponse($rotateRefreshToken, $revokeRotatedRefreshToken)
 {
     $grant = new RefreshTokenGrant($this->accessTokenService, $this->refreshTokenService, ServerOptions::fromArray(['rotate_refresh_tokens' => $rotateRefreshToken, 'revoke_rotated_refresh_tokens' => $revokeRotatedRefreshToken]));
     $request = $this->createMock(ServerRequestInterface::class);
     $request->expects($this->once())->method('getParsedBody')->willReturn(['refresh_token' => '123', 'scope' => 'read']);
     $owner = $this->createMock(TokenOwnerInterface::class);
     $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1));
     $refreshToken = $this->getValidRefreshToken($owner, ['read']);
     $this->refreshTokenService->expects($this->once())->method('getToken')->with('123')->will($this->returnValue($refreshToken));
     if ($rotateRefreshToken) {
         $this->refreshTokenService->expects($revokeRotatedRefreshToken ? $this->once() : $this->never())->method('deleteToken')->with($refreshToken);
         $refreshToken = $this->getValidRefreshToken();
         $this->refreshTokenService->expects($this->once())->method('createToken')->will($this->returnValue($refreshToken));
     }
     $accessToken = $this->getValidAccessToken($owner);
     $this->accessTokenService->expects($this->once())->method('createToken')->will($this->returnValue($accessToken));
     $response = $grant->createTokenResponse($request, Client::createNewClient('name', []));
     $body = json_decode($response->getBody(), true);
     $this->assertEquals('azerty_access', $body['access_token']);
     $this->assertEquals('Bearer', $body['token_type']);
     $this->assertEquals(3600, $body['expires_in']);
     $this->assertEquals('read', $body['scope']);
     $this->assertEquals(1, $body['owner_id']);
     $this->assertEquals('azerty_refresh', $body['refresh_token']);
 }
 /**
  * @dataProvider hasRefreshGrant
  */
 public function testCanCreateTokenResponse($hasRefreshGrant)
 {
     $request = $this->createMock(ServerRequestInterface::class);
     $request->expects($this->once())->method('getParsedBody')->willReturn(['username' => 'michael', 'password' => 'azerty', 'scope' => 'read']);
     $owner = $this->createMock(TokenOwnerInterface::class);
     $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1));
     $callable = function ($username, $password) use($owner) {
         return $owner;
     };
     $accessToken = $this->getValidAccessToken($owner);
     $this->accessTokenService->expects($this->once())->method('createToken')->will($this->returnValue($accessToken));
     if ($hasRefreshGrant) {
         $refreshToken = $this->getValidRefreshToken();
         $this->refreshTokenService->expects($this->once())->method('createToken')->will($this->returnValue($refreshToken));
     }
     $authorizationServer = $this->createMock(AuthorizationServer::class);
     $authorizationServer->expects($this->once())->method('hasGrant')->with(RefreshTokenGrant::GRANT_TYPE)->will($this->returnValue($hasRefreshGrant));
     $this->grant = new PasswordGrant($this->accessTokenService, $this->refreshTokenService, $callable);
     $this->grant->setAuthorizationServer($authorizationServer);
     $response = $this->grant->createTokenResponse($request, Client::createNewClient('id', 'http://www.example.com'));
     $body = json_decode($response->getBody(), true);
     $this->assertEquals('azerty_access', $body['access_token']);
     $this->assertEquals('Bearer', $body['token_type']);
     $this->assertEquals(3600, $body['expires_in']);
     $this->assertEquals('read', $body['scope']);
     $this->assertEquals(1, $body['owner_id']);
     if ($hasRefreshGrant) {
         $this->assertEquals('azerty_refresh', $body['refresh_token']);
     }
 }
 /**
  * @dataProvider hasRefreshGrant
  */
 public function testCanCreateTokenResponse($hasRefreshGrant)
 {
     $request = $this->createMock(ServerRequestInterface::class);
     $request->expects($this->once())->method('getParsedBody')->willReturn(['code' => '123', 'client_id' => 'client_123']);
     $client = Client::reconstitute(['id' => 'client_123', 'name' => 'name', 'secret' => '', 'redirectUris' => []]);
     $token = $this->getValidAuthorizationCode(null, null, $client);
     $this->authorizationCodeService->expects($this->once())->method('getToken')->with('123')->will($this->returnValue($token));
     $owner = $this->createMock(TokenOwnerInterface::class);
     $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1));
     $accessToken = $this->getValidAccessToken($owner);
     $this->accessTokenService->expects($this->once())->method('createToken')->will($this->returnValue($accessToken));
     if ($hasRefreshGrant) {
         $refreshToken = $this->getValidRefreshToken();
         $this->refreshTokenService->expects($this->once())->method('createToken')->will($this->returnValue($refreshToken));
     }
     $authorizationServer = $this->createMock(AuthorizationServer::class);
     $authorizationServer->expects($this->once())->method('hasGrant')->with(RefreshTokenGrant::GRANT_TYPE)->will($this->returnValue($hasRefreshGrant));
     $this->grant = new AuthorizationGrant($this->authorizationCodeService, $this->accessTokenService, $this->refreshTokenService);
     $this->grant->setAuthorizationServer($authorizationServer);
     $response = $this->grant->createTokenResponse($request, $client, $owner);
     $body = json_decode($response->getBody(), true);
     $this->assertEquals('azerty_access', $body['access_token']);
     $this->assertEquals('Bearer', $body['token_type']);
     $this->assertEquals(3600, $body['expires_in']);
     $this->assertEquals('read', $body['scope']);
     $this->assertEquals(1, $body['owner_id']);
     if ($hasRefreshGrant) {
         $this->assertEquals('azerty_refresh', $body['refresh_token']);
     }
 }
 /**
  * {@inheritDoc}
  * @throws OAuth2Exception
  */
 public function createTokenResponse(ServerRequestInterface $request, Client $client = null, TokenOwnerInterface $owner = null) : ResponseInterface
 {
     $postParams = $request->getParsedBody();
     $code = $postParams['code'] ?? null;
     if (null === $code) {
         throw OAuth2Exception::invalidRequest('Could not find the authorization code in the request');
     }
     /* @var \ZfrOAuth2\Server\Model\AuthorizationCode $authorizationCode */
     $authorizationCode = $this->authorizationCodeService->getToken($code);
     if (null === $authorizationCode || $authorizationCode->isExpired()) {
         throw OAuth2Exception::invalidGrant('Authorization code cannot be found or is expired');
     }
     $clientId = $postParams['client_id'] ?? null;
     if ($authorizationCode->getClient()->getId() !== $clientId) {
         throw OAuth2Exception::invalidRequest('Authorization code\'s client does not match with the one that created the authorization code');
     }
     // If owner is null, we reuse the same as the authorization code
     $owner = $owner ?: $authorizationCode->getOwner();
     // Everything is okey, let's start the token generation!
     $scopes = $authorizationCode->getScopes();
     // reuse the scopes from the authorization code
     $accessToken = $this->accessTokenService->createToken($owner, $client, $scopes);
     // Before generating a refresh token, we must make sure the authorization server supports this grant
     $refreshToken = null;
     if ($this->authorizationServer->hasGrant(RefreshTokenGrant::GRANT_TYPE)) {
         $refreshToken = $this->refreshTokenService->createToken($owner, $client, $scopes);
     }
     return $this->prepareTokenResponse($accessToken, $refreshToken);
 }
 public function testCreateNewTokenUntilOneDoesNotExist()
 {
     $this->scopeService->expects($this->once())->method('getDefaultScopes')->will($this->returnValue(['read']));
     $this->tokenRepository->expects($this->at(0))->method('tokenExists')->with($this->isType('string'))->willReturn(true);
     $this->tokenRepository->expects($this->at(1))->method('tokenExists')->with($this->isType('string'))->willReturn(false);
     $this->tokenRepository->expects($this->once())->method('save')->will($this->returnArgument(0));
     $owner = $this->createMock(TokenOwnerInterface::class);
     $client = $this->createMock(Client::class);
     $token = $this->tokenService->createToken($owner, $client, []);
     $this->assertEquals(40, strlen($token->getToken()));
 }
 /**
  * @throws OAuth2Exception (invalid_request) If no "token" is present
  * @throws OAuth2Exception (unsupported_token_type) If "token" is unsupported
  * @throws OAuth2Exception (invalid_client) If "token" was issued for another client and cannot be revoked
  */
 public function handleRevocationRequest(ServerRequestInterface $request) : ResponseInterface
 {
     $postParams = $request->getParsedBody();
     $token = $postParams['token'] ?? null;
     $tokenHint = $postParams['token_type_hint'] ?? null;
     if (null === $token || null === $tokenHint) {
         throw OAuth2Exception::invalidRequest('Cannot revoke a token as the "token" and/or "token_type_hint" parameters are missing');
     }
     if ($tokenHint !== 'access_token' && $tokenHint !== 'refresh_token') {
         throw OAuth2Exception::unsupportedTokenType(sprintf('Authorization server does not support revocation of token of type "%s"', $tokenHint));
     }
     if ($tokenHint === 'access_token') {
         $token = $this->accessTokenService->getToken((string) $token);
     } else {
         $token = $this->refreshTokenService->getToken((string) $token);
     }
     $response = new Response();
     // According to spec, we should return 200 if token is invalid
     if (null === $token) {
         return $response;
     }
     // Now, we must validate the client if the token was generated against a non-public client
     if (null !== $token->getClient() && !$token->getClient()->isPublic()) {
         $requestClient = $this->getClient($request, false);
         if ($requestClient !== $token->getClient()) {
             throw OAuth2Exception::invalidClient('Token was issued for another client and cannot be revoked');
         }
     }
     try {
         if ($tokenHint === 'access_token') {
             $this->accessTokenService->deleteToken($token);
         } else {
             $this->refreshTokenService->deleteToken($token);
         }
     } catch (Throwable $exception) {
         // According to spec (https://tools.ietf.org/html/rfc7009#section-2.2.1), we should return a server 503
         // error if we cannot delete the token for any reason
         $response = $response->withStatus(503, 'An error occurred while trying to delete the token');
     }
     return $response;
 }
Example #8
0
 /**
  * @throws OAuth2Exception
  */
 public function createTokenResponse(ServerRequestInterface $request, Client $client = null, TokenOwnerInterface $owner = null) : ResponseInterface
 {
     $postParams = $request->getParsedBody();
     // Validate the user using its username and password
     $username = $postParams['username'] ?? null;
     $password = $postParams['password'] ?? null;
     $scope = $postParams['scope'] ?? null;
     if (null === $username || null == $password) {
         throw OAuth2Exception::invalidRequest('Username and/or password is missing');
     }
     $callback = $this->callback;
     $owner = $callback($username, $password);
     if (!$owner instanceof TokenOwnerInterface) {
         throw OAuth2Exception::accessDenied('Either username or password are incorrect');
     }
     // Everything is okay, we can start tokens generation!
     $accessToken = $this->accessTokenService->createToken($owner, $client, $scope);
     // Before generating a refresh token, we must make sure the authorization server supports this grant
     $refreshToken = null;
     if ($this->authorizationServer->hasGrant(RefreshTokenGrant::GRANT_TYPE)) {
         $refreshToken = $this->refreshTokenService->createToken($owner, $client, $scope);
     }
     return $this->prepareTokenResponse($accessToken, $refreshToken);
 }