/** * {@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); } }