/**
  * {@inheritdoc}
  */
 public function findClient(ServerRequestInterface $request, &$client_credentials = null)
 {
     $client_id = RequestBody::getParameter($request, 'client_id');
     $client_secret = RequestBody::getParameter($request, 'client_secret');
     if (!empty($client_id) && !empty($client_secret)) {
         $client_credentials = $client_secret;
         return $client_id;
     }
 }
 /**
  * {@inheritdoc}
  */
 public function grantAccessToken(ServerRequestInterface $request, ClientInterface $client, GrantTypeResponseInterface &$grant_type_response)
 {
     if (!$client instanceof ConfidentialClientInterface) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_CLIENT, 'The client is not a confidential client');
     }
     $issue_refresh_token = $this->getConfiguration()->get('issue_refresh_token_with_client_credentials_grant_type', false);
     $scope = RequestBody::getParameter($request, 'scope');
     $grant_type_response->setRequestedScope($scope);
     $grant_type_response->setAvailableScope(null);
     $grant_type_response->setResourceOwnerPublicId($client->getPublicId());
     $grant_type_response->setRefreshTokenIssued($issue_refresh_token);
     $grant_type_response->setRefreshTokenScope($scope);
     $grant_type_response->setRefreshTokenRevoked(null);
 }
 /**
  * {@inheritdoc}
  */
 public function grantAccessToken(ServerRequestInterface $request, ClientInterface $client, GrantTypeResponseInterface &$grant_type_response)
 {
     $username = RequestBody::getParameter($request, 'username');
     $password = RequestBody::getParameter($request, 'password');
     $end_user = $this->getEndUserManager()->getEndUser($username);
     if (null === $end_user || !$this->getEndUserManager()->checkEndUserPasswordCredentials($end_user, $password)) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_GRANT, 'Invalid username and password combination');
     }
     $scope = RequestBody::getParameter($request, 'scope');
     $grant_type_response->setRequestedScope($scope);
     $grant_type_response->setAvailableScope(null);
     $grant_type_response->setResourceOwnerPublicId($end_user->getPublicId());
     $grant_type_response->setRefreshTokenIssued($this->getIssueRefreshToken($client, $end_user));
     $grant_type_response->setRefreshTokenScope($scope);
     $grant_type_response->setRefreshTokenRevoked(null);
 }
 /**
  * {@inheritdoc}
  */
 public function prepareGrantTypeResponse(ServerRequestInterface $request, GrantTypeResponseInterface &$grant_type_response)
 {
     $assertion = RequestBody::getParameter($request, 'assertion');
     try {
         Assertion::notNull($assertion, 'Parameter "assertion" is missing.');
         $jwt = $this->getJWTLoader()->load($assertion, $this->key_encryption_key_set, $this->encryption_required);
         Assertion::isInstanceOf($jwt, JWSInterface::class, 'Assertion does not contain signed claims.');
         Assertion::true($jwt->hasClaim('sub'), 'Assertion does not contain "sub" claims.');
     } catch (\Exception $e) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_REQUEST, $e->getMessage());
     }
     //We modify the response:
     // - We add the subject as the client public id
     // - We transmit the JWT to the response for further needs
     $grant_type_response->setClientPublicId($jwt->getClaim('sub'));
     $grant_type_response->setAdditionalData('jwt', $jwt);
 }
 /**
  * {@inheritdoc}
  */
 public function grantAccessToken(ServerRequestInterface $request, ClientInterface $client, GrantTypeResponseInterface &$grant_type_response)
 {
     $refresh_token = RequestBody::getParameter($request, 'refresh_token');
     if (null === $refresh_token) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_REQUEST, 'No "refresh_token" parameter found');
     }
     $token = $this->getRefreshTokenManager()->getRefreshToken($refresh_token);
     if (!$token instanceof RefreshTokenInterface || $token->isUsed()) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_GRANT, 'Invalid refresh token');
     }
     $this->checkRefreshToken($token, $client);
     $grant_type_response->setRequestedScope(RequestBody::getParameter($request, 'scope') ?: $token->getScope());
     $grant_type_response->setAvailableScope($token->getScope());
     $grant_type_response->setResourceOwnerPublicId($token->getResourceOwnerPublicId());
     $grant_type_response->setRefreshTokenIssued(true);
     $grant_type_response->setRefreshTokenScope($token->getScope());
     $grant_type_response->setRefreshTokenRevoked($token);
 }
 /**
  * {@inheritdoc}
  */
 public function grantAccessToken(ServerRequestInterface $request, ClientInterface $client, GrantTypeResponseInterface &$grant_type_response)
 {
     $refresh_token = RequestBody::getParameter($request, 'refresh_token');
     if (null === $refresh_token) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_REQUEST, 'No "refresh_token" parameter found');
     }
     $token = $this->getRefreshTokenManager()->getRefreshToken($refresh_token);
     if (!$token instanceof RefreshTokenInterface) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_GRANT, 'Invalid refresh token');
     }
     $this->checkRefreshToken($token, $client);
     if (empty($grant_type_response->getRequestedScope())) {
         $grant_type_response->setRequestedScope($token->getScope());
     }
     $grant_type_response->setAvailableScope($token->getScope());
     $grant_type_response->setResourceOwnerPublicId($token->getResourceOwnerPublicId());
     $grant_type_response->setUserAccountPublicId($token->getUserAccountPublicId());
     $grant_type_response->setRefreshTokenIssued(true);
     $grant_type_response->setRefreshTokenScope($token->getScope());
     $grant_type_response->setRefreshTokenRevoked($token);
     $grant_type_response->setAdditionalData('metadatas', $token->getMetadatas());
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param string                                   $token
  * @param string|null                              $token_type_hint
  * @param string|null                              $callback
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 private function getParameters(ServerRequestInterface $request, &$token, &$token_type_hint, &$callback)
 {
     $query_params = $request->getQueryParams();
     $body_params = RequestBody::getParameters($request);
     foreach (['token', 'token_type_hint', 'callback'] as $key) {
         ${$key} = array_key_exists($key, $query_params) ? $query_params[$key] : (array_key_exists($key, $body_params) ? $body_params[$key] : null);
     }
 }
 /**
  * {@inheritdoc}
  */
 public function findClient(ServerRequestInterface $request, &$client_credentials = null)
 {
     $client_assertion_type = RequestBody::getParameter($request, 'client_assertion_type');
     //We verify the client assertion type in the request
     if ('urn:ietf:params:oauth:client-assertion-type:jwt-bearer' !== $client_assertion_type) {
         return;
     }
     $client_assertion = RequestBody::getParameter($request, 'client_assertion');
     try {
         //We verify the client assertion exists
         Assertion::notNull($client_assertion, 'Parameter "client_assertion" is missing.');
         //We load the assertion
         $jwt = $this->getJWTLoader()->load($client_assertion, $this->key_encryption_key_set, $this->encryption_required);
         $diff = array_diff(['iss', 'sub', 'aud', 'jti', 'exp'], array_keys($jwt->getClaims()));
         Assertion::eq(0, count($diff), sprintf('The following claim(s) is/are mandatory: "%s".', json_encode(array_values($diff))));
         Assertion::eq($jwt->getClaim('sub'), $jwt->getClaim('iss'), 'The claims "sub" and "iss" must contain the client public ID.');
     } catch (\Exception $e) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_REQUEST, $e->getMessage());
     }
     $client_credentials = $jwt;
     return $jwt->getClaim('sub');
 }
 /**
  * {@inheritdoc}
  */
 public function grantAccessToken(ServerRequestInterface $request, ClientInterface $client, GrantTypeResponseInterface &$grant_type_response)
 {
     $username = RequestBody::getParameter($request, 'username');
     $password = RequestBody::getParameter($request, 'password');
     $user_account = $this->getUserAccountManager()->getUserAccountByUsername($username);
     if (null === $user_account || !$this->getUserAccountManager()->checkUserAccountPasswordCredentials($user_account, $password)) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_GRANT, 'Invalid username and password combination');
     }
     $grant_type_response->setResourceOwnerPublicId($user_account->getUserPublicId());
     $grant_type_response->setUserAccountPublicId($user_account->getPublicId());
     $grant_type_response->setRefreshTokenIssued($this->issueRefreshToken($client));
     $grant_type_response->setRefreshTokenScope($grant_type_response->getRequestedScope());
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \OAuth2\Grant\GrantTypeResponseInterface $grant_type_response
  */
 private function populateScope(ServerRequestInterface $request, GrantTypeResponseInterface &$grant_type_response)
 {
     $scope = RequestBody::getParameter($request, 'scope');
     if (null !== $scope) {
         $scope = $this->getScopeManager()->convertToArray($scope);
         $grant_type_response->setRequestedScope($scope);
     }
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \Psr\Http\Message\ResponseInterface      $response
  * @param \OAuth2\Client\ClientInterface           $client
  */
 private function handlePut(ServerRequestInterface $request, ResponseInterface &$response, ClientInterface $client)
 {
     $request_parameters = RequestBody::getParameters($request);
     $this->checkPreservedParameters($request_parameters);
     $this->checkSoftwareStatement($request_parameters);
     $client_data = $client->all();
     foreach (['registration_access_token', 'registration_client_uri', 'client_secret_expires_at', 'client_id_issued_at'] as $k) {
         if (array_key_exists($k, $client_data)) {
             unset($client_data[$k]);
         }
     }
     $diff_data = array_diff_key($client_data, $request_parameters);
     Assertion::true(empty($diff_data), 'The request must include all client metadata fields.');
     Assertion::eq($request_parameters['client_id'], $client->getPublicId(), 'Inconsistent "client_id" parameter.');
     unset($request_parameters['client_id']);
     $request_parameters = array_merge($request_parameters, ['registration_access_token' => null, 'registration_client_uri' => null, 'client_secret_expires_at' => null]);
     foreach ($request_parameters as $k => $v) {
         if (empty($v)) {
             $client->remove($k);
             unset($request_parameters[$k]);
         }
     }
     $this->getClientRuleManager()->processParametersForClient($client, $request_parameters);
     $this->getClientManager()->saveClient($client);
     $this->processResponseWithClient($response, $client);
 }
 /**
  * Get the token from the request body.
  *
  * @param \Psr\Http\Message\ServerRequestInterface $request
  *
  * @return string|null
  */
 protected function getTokenFromRequestBody(ServerRequestInterface $request)
 {
     return RequestBody::getParameter($request, 'access_token');
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \OAuth2\Token\AuthCodeInterface          $authCode
  * @param \OAuth2\Client\ClientInterface           $client
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 private function checkPKCE(ServerRequestInterface $request, AuthCodeInterface $authCode, ClientInterface $client)
 {
     $params = $authCode->getQueryParams();
     if (!array_key_exists('code_challenge', $params)) {
         if (true === $this->isPKCEForPublicClientsEnforced() && $client->isPublic()) {
             throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_REQUEST, 'Non-confidential clients must set a proof key (PKCE) for code exchange.');
         }
         return;
     }
     $code_challenge = $params['code_challenge'];
     $code_challenge_method = array_key_exists('code_challenge_method', $params) ? $params['code_challenge_method'] : 'plain';
     $code_verifier = RequestBody::getParameter($request, 'code_verifier');
     try {
         $this->getPKCEMethodManager()->checkPKCEInput($code_challenge_method, $code_challenge, $code_verifier);
     } catch (\InvalidArgumentException $e) {
         throw $this->getExceptionManager()->getBadRequestException(ExceptionManagerInterface::ERROR_INVALID_REQUEST, $e->getMessage());
     }
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \Psr\Http\Message\ResponseInterface      $response
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 private function handleRequest(ServerRequestInterface $request, ResponseInterface &$response)
 {
     $initial_access_token = $this->findInitialAccessToken($request);
     $request_parameters = RequestBody::getParameters($request);
     $this->checkSoftwareStatement($request_parameters);
     $client = $this->getClientManager()->createClient();
     $this->getClientRuleManager()->processParametersForClient($client, $request_parameters);
     if (null !== $initial_access_token) {
         $client->setResourceOwnerPublicId($initial_access_token->getUserAccountPublicId());
     }
     $this->getClientManager()->saveClient($client);
     $this->processResponse($response, $client);
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  *
  * @return \Jose\Object\JWSInterface
  */
 protected function findCredentialsFromClientAssertion(ServerRequestInterface $request)
 {
     $client_assertion_type = RequestBody::getParameter($request, 'client_assertion_type');
     //We verify the client assertion type in the request
     if ('urn:ietf:params:oauth:client-assertion-type:jwt-bearer' !== $client_assertion_type) {
         return;
     }
     $client_assertion = RequestBody::getParameter($request, 'client_assertion');
     //We verify the client assertion exists
     if (null === $client_assertion) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_REQUEST, 'Parameter "client_assertion" is missing.');
     }
     //We load the assertion
     $jwt = $this->getJWTLoader()->load($client_assertion);
     return $jwt;
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \OAuth2\Token\AuthCodeInterface          $authCode
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 protected function checkPKCE(ServerRequestInterface $request, AuthCodeInterface $authCode)
 {
     $params = $authCode->getQueryParams();
     if (!array_key_exists('code_challenge', $params)) {
         return;
     }
     $code_verifier = RequestBody::getParameter($request, 'code_verifier');
     if (null === $code_verifier) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_REQUEST, 'The parameter "code_verifier" is required.');
     }
     $code_challenge = $params['code_challenge'];
     $code_challenge_method = array_key_exists('code_challenge_method', $params) ? $params['code_challenge'] : 'plain';
     if (!in_array($code_challenge_method, ['plain', 'S256'])) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_REQUEST, 'Unsupported "code_challenge_method".');
     }
     $calculated = 'plain' === $code_challenge_method ? $code_verifier : Base64Url::encode(hash('sha256', $code_verifier, true));
     if (!hash_equals($code_challenge, $calculated)) {
         throw $this->getExceptionManager()->getException(ExceptionManagerInterface::BAD_REQUEST, ExceptionManagerInterface::INVALID_REQUEST, 'Invalid parameter "code_verifier".');
     }
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param string|null                              $token
  * @param string|null                              $token_type_hint
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 private function getParameters(ServerRequestInterface $request, &$token, &$token_type_hint)
 {
     $query_params = $request->getQueryParams();
     $body_params = RequestBody::getParameters($request);
     $token = array_key_exists('token', $query_params) ? $query_params['token'] : (array_key_exists('token', $body_params) ? $body_params['token'] : null);
     $token_type_hint = array_key_exists('token_type_hint', $query_params) ? $query_params['token_type_hint'] : (array_key_exists('token_type_hint', $body_params) ? $body_params['token_type_hint'] : null);
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  *
  * @return string[]|null
  */
 protected function findCredentialsFromRequestBody(ServerRequestInterface $request)
 {
     $client_id = RequestBody::getParameter($request, 'client_id');
     $client_secret = RequestBody::getParameter($request, 'client_secret');
     if (null !== $client_id && null !== $client_secret) {
         return ['client_id' => $client_id, 'client_credentials' => $client_secret];
     }
 }
 /**
  * @param \Psr\Http\Message\ServerRequestInterface $request
  * @param \Psr\Http\Message\ResponseInterface      $response
  *
  * @throws \OAuth2\Exception\BaseExceptionInterface
  */
 protected function handleRequest(ServerRequestInterface $request, ResponseInterface &$response)
 {
     $grant_type = RequestBody::getParameter($request, 'grant_type');
     $type = $this->getGrantType($grant_type);
     $grant_type_response = new GrantTypeResponse();
     $type->prepareGrantTypeResponse($request, $grant_type_response);
     $client = $this->findClient($request, $grant_type_response);
     $this->checkGrantType($client, $grant_type);
     $grant_type_response->setClientPublicId($client->getPublicId());
     $type->grantAccessToken($request, $client, $grant_type_response);
     $result = ['requested_scope' => $grant_type_response->getRequestedScope() ?: $this->getScopeManager()->getDefaultScopes($client), 'available_scope' => $grant_type_response->getAvailableScope() ?: $this->getScopeManager()->getAvailableScopes($client), 'resource_owner_public_id' => $grant_type_response->getResourceOwnerPublicid(), 'refresh_token' => ['issued' => $grant_type_response->isRefreshTokenIssued(), 'scope' => $grant_type_response->getRefreshTokenScope(), 'used' => $grant_type_response->getRefreshTokenRevoked()]];
     foreach (['requested_scope', 'available_scope'] as $key) {
         $result[$key] = $this->getScopeManager()->convertToScope($result[$key]);
     }
     //Modify the scope according to the scope policy
     $result['requested_scope'] = $this->getScopeManager()->checkScopePolicy($client, $result['requested_scope'], $request);
     //Check if scope requested are within the available scope
     if (!$this->getScopeManager()->checkScopes($result['requested_scope'], $result['available_scope'])) {
         throw $this->getExceptionManager()->getException('BadRequest', 'invalid_scope', 'An unsupported scope was requested. Available scopes are [' . implode(',', $result['available_scope']) . ']');
     }
     //Create and return access token (with refresh token and other information if asked) as an array
     $token = $this->createAccessToken($client, $result);
     $prepared = $this->getAccessTokenTypeManager()->getDefaultAccessTokenType()->prepareAccessToken($token);
     $response->getBody()->write(json_encode($prepared));
     $response = $response->withStatus(200);
     $headers = ['Content-Type' => 'application/json', 'Cache-Control' => 'no-store, private', 'Pragma' => 'no-cache'];
     foreach ($headers as $key => $value) {
         $response = $response->withHeader($key, $value);
     }
 }