/** * {@inheritDoc} */ public function createTokenResponse(Request $request, Client $client = null, TokenOwnerInterface $owner = null) { $token = $request->getPost('access_token'); $scope = $request->getPost('scope'); if (null === $token) { throw OAuth2Exception::invalidRequest('Missing parameter access_token'); } $owner = $this->getOwner($token); if (!$owner instanceof TokenOwnerInterface) { throw OAuth2Exception::accessDenied('Unable to load user from this token'); } /** * @var AccessToken $accessToken * @var null|RefreshToken $refreshToken * */ $accessToken = new AccessToken(); $refreshToken = null; // Generate token $this->populateToken($accessToken, $client, $owner, $scope); $accessToken = $this->accessTokenService->createToken($accessToken); // Before generating a refresh token, we must make sure the authorization server supports this grant if ($this->authorizationServer->hasGrant(RefreshTokenGrant::GRANT_TYPE)) { $refreshToken = new RefreshToken(); $this->populateToken($refreshToken, $client, $owner, $scope); $refreshToken = $this->refreshTokenService->createToken($refreshToken); } return $this->prepareTokenResponse($accessToken, $refreshToken); }
/** * {@inheritDoc} */ public function createTokenResponse(ServerRequestInterface $request, Client $client = null, TokenOwnerInterface $owner = null) : ResponseInterface { $postParams = $request->getParsedBody(); // Everything is okey, we can start tokens generation! $scope = $postParams['scope'] ?? null; $accessToken = new AccessToken(); $this->populateToken($accessToken, $client, $owner, $scope); $accessToken = $this->accessTokenService->createToken($accessToken); return $this->prepareTokenResponse($accessToken); }
/** * Get the access token * * Note that this method will only match tokens that are not expired and match the given scopes (if any). * If no token is pass, this method will return null, but if a token is given does not exist (ie. has been * deleted) or is not valid, then it will trigger an exception * * @link http://tools.ietf.org/html/rfc6750#page-5 * @param ServerRequestInterface $request * @param array $scopes * @return AccessToken|null * @throws Exception\InvalidAccessTokenException If given access token is invalid or expired */ public function getAccessToken(ServerRequestInterface $request, $scopes = []) { if (!($token = $this->extractAccessToken($request))) { return null; } $token = $this->accessTokenService->getToken($token); if ($token === null || !$token->isValid($scopes)) { throw new InvalidAccessTokenException('Access token has expired or has been deleted'); } return $token; }
/** * @param ContainerInterface $container * @return TokenService */ public function __invoke(ContainerInterface $container) : TokenService { /** @var ServerOptions $serverOptions */ $serverOptions = $container->get(ServerOptions::class); /** @var AccessTokenRepositoryInterface $tokenRepository */ $tokenRepository = $container->get(AccessTokenRepositoryInterface::class); /* @var ScopeService $scopeService */ $scopeService = $container->get(ScopeService::class); $service = new TokenService($tokenRepository, $scopeService); $service->setTokenTTL($serverOptions->getAccessTokenTtl()); return $service; }
/** * {@inheritDoc} */ public function createService(ServiceLocatorInterface $serviceLocator) { /* @var \ZfrOAuth2Module\Server\Options\ModuleOptions $options */ $options = $serviceLocator->get('ZfrOAuth2Module\\Server\\Options\\ModuleOptions'); /* @var \Doctrine\Common\Persistence\ObjectManager $objectManager */ $objectManager = $serviceLocator->get($options->getObjectManager()); $tokenRepository = $objectManager->getRepository('ZfrOAuth2\\Server\\Entity\\AuthorizationCode'); /* @var \ZfrOAuth2\Server\Service\ScopeService $scopeService */ $scopeService = $serviceLocator->get('ZfrOAuth2\\Server\\Service\\ScopeService'); $authorizationCodeService = new TokenService($objectManager, $tokenRepository, $scopeService); $authorizationCodeService->setTokenTTL($options->getAuthorizationCodeTtl()); return $authorizationCodeService; }
/** * @dataProvider rotateRefreshToken */ public function testCanCreateTokenResponse($rotateRefreshToken) { $request = $this->getMock(ServerRequestInterface::class); $request->expects($this->once())->method('getParsedBody')->willReturn(['refresh_token' => '123', 'scope' => 'read']); $owner = $this->getMock(TokenOwnerInterface::class); $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1)); $refreshToken = $this->getValidRefreshToken(); $refreshToken->setScopes(['read']); $refreshToken->setOwner($owner); $this->refreshTokenService->expects($this->once())->method('getToken')->with('123')->will($this->returnValue($refreshToken)); if ($rotateRefreshToken) { $this->refreshTokenService->expects($this->once())->method('deleteToken')->with($refreshToken); $refreshToken = $this->getValidRefreshToken(); $this->refreshTokenService->expects($this->once())->method('createToken')->will($this->returnValue($refreshToken)); } $accessToken = $this->getValidAccessToken(); $accessToken->setOwner($owner); $this->accessTokenService->expects($this->once())->method('createToken')->will($this->returnValue($accessToken)); $this->grant->setRotateRefreshTokens($rotateRefreshToken); $response = $this->grant->createTokenResponse($request, new Client()); $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']); }
/** * {@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\Entity\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 = new AccessToken(); $this->populateToken($accessToken, $client, $owner, $scopes); $accessToken = $this->accessTokenService->createToken($accessToken); // 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 = new RefreshToken(); $this->populateToken($refreshToken, $client, $owner, $scopes); $refreshToken = $this->refreshTokenService->createToken($refreshToken); } return $this->prepareTokenResponse($accessToken, $refreshToken); }
/** * {@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($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 = new AccessToken(); $this->populateToken($accessToken, $client, $owner, $scopes); /** @var AccessToken $accessToken */ $accessToken = $this->accessTokenService->createToken($accessToken); // We may want to revoke the old refresh token if ($this->rotateRefreshTokens) { $this->refreshTokenService->deleteToken($refreshToken); $refreshToken = new RefreshToken(); $this->populateToken($refreshToken, $client, $owner, $scopes); $refreshToken = $this->refreshTokenService->createToken($refreshToken); } // We can generate the response! return $this->prepareTokenResponse($accessToken, $refreshToken, true); }
/** * @dataProvider hasRefreshGrant */ public function testCanCreateTokenResponse($hasRefreshGrant) { $request = $this->getMock(ServerRequestInterface::class); $request->expects($this->once())->method('getParsedBody')->willReturn(['username' => 'michael', 'password' => 'azerty', 'scope' => 'read']); $owner = $this->getMock(TokenOwnerInterface::class); $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1)); $callable = function ($username, $password) use($owner) { return $owner; }; $accessToken = $this->getValidAccessToken(); $accessToken->setOwner($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->getMock(AuthorizationServer::class, [], [], '', false); $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, new Client()); $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(); // 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 = new AccessToken(); $this->populateToken($accessToken, $client, $owner, $scope); $accessToken = $this->accessTokenService->createToken($accessToken); // 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 = new RefreshToken(); $this->populateToken($refreshToken, $client, $owner, $scope); $refreshToken = $this->refreshTokenService->createToken($refreshToken); } return $this->prepareTokenResponse($accessToken, $refreshToken); }
public function testCanCreateTokenResponse() { $request = $this->getMock(ServerRequestInterface::class); $client = new Client(); $owner = $this->getMock(TokenOwnerInterface::class); $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1)); $token = new AccessToken(); $token->setToken('azerty'); $token->setOwner($owner); $token->setExpiresAt((new DateTime())->add(new DateInterval('PT1H'))); $this->tokenService->expects($this->once())->method('createToken')->will($this->returnValue($token)); $response = $this->grant->createTokenResponse($request, $client, $owner); $body = json_decode($response->getBody(), true); $this->assertEquals('azerty', $body['access_token']); $this->assertEquals('Bearer', $body['token_type']); $this->assertEquals(3600, $body['expires_in']); $this->assertEquals(1, $body['owner_id']); }
public function testCreateNewTokenUntilOneDoesNotExist() { $token = new AccessToken(); $this->scopeService->expects($this->once())->method('getDefaultScopes')->will($this->returnValue(['read'])); $this->tokenRepository->expects($this->at(0))->method('findByToken')->with($this->isType('string'))->will($this->returnValue(new AccessToken())); $this->tokenRepository->expects($this->at(1))->method('findByToken')->with($this->isType('string'))->will($this->returnValue(null)); $this->tokenService->createToken($token); $this->assertEquals(40, strlen($token->getToken())); }
/** * @param ServerRequestInterface $request * @return ResponseInterface * @throws OAuth2Exception If no "token" is present */ 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($token); } else { $token = $this->refreshTokenService->getToken($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 (\Exception $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; }
/** * @dataProvider requestProvider */ public function testCanValidateAccessToResource($expiredToken, $tokenScope, $desiredScope, $match) { $request = $this->getMock(ServerRequestInterface::class); $request->expects($this->once())->method('hasHeader')->with('Authorization')->will($this->returnValue(true)); $request->expects($this->once())->method('getHeaderLine')->will($this->returnValue('Bearer token')); $accessToken = new AccessToken(); $date = new DateTime(); if ($expiredToken) { $date->sub(new DateInterval('P1D')); } else { $date->add(new DateInterval('P1D')); } $accessToken->setExpiresAt($date); $accessToken->setScopes($tokenScope); $this->tokenService->expects($this->once())->method('getToken')->with('token')->will($this->returnValue($accessToken)); if (!$match || $expiredToken) { $this->setExpectedException(InvalidAccessTokenException::class); } $tokenResult = $this->resourceServer->getAccessToken($request, $desiredScope); $this->assertInstanceOf(AccessToken::class, $tokenResult); }
/** * @dataProvider hasRefreshGrant */ public function testCanCreateTokenResponse($hasRefreshGrant) { $request = $this->getMock(ServerRequestInterface::class); $request->expects($this->once())->method('getParsedBody')->willReturn(['code' => '123', 'client_id' => 'client_123']); $token = $this->getValidAuthorizationCode(); $client = new Client(); // We use reflection because there is no setter on client $reflProperty = new \ReflectionProperty($client, 'id'); $reflProperty->setAccessible(true); $reflProperty->setValue($client, 'client_123'); $token->setClient($client); $this->authorizationCodeService->expects($this->once())->method('getToken')->with('123')->will($this->returnValue($token)); $owner = $this->getMock(TokenOwnerInterface::class); $owner->expects($this->once())->method('getTokenOwnerId')->will($this->returnValue(1)); $accessToken = $this->getValidAccessToken(); $accessToken->setOwner($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->getMock(AuthorizationServer::class, [], [], '', false); $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, new 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']); } }