mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Merge branch 'V5-WIP' into secure_body_params_access
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract grant
|
||||
* OAuth 2.0 Abstract grant.
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\Event\EmitterAwareTrait;
|
||||
@@ -21,13 +20,15 @@ use League\OAuth2\Server\Entities\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entities\ScopeEntity;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\Utils\SecureKey;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Abstract grant class
|
||||
* Abstract grant class.
|
||||
*/
|
||||
abstract class AbstractGrant implements GrantTypeInterface
|
||||
{
|
||||
@@ -35,13 +36,6 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
|
||||
const SCOPE_DELIMITER_STRING = ' ';
|
||||
|
||||
/**
|
||||
* Grant responds with
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $respondsWith = 'token';
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
*/
|
||||
@@ -62,6 +56,16 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface
|
||||
*/
|
||||
private $authCodeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
|
||||
*/
|
||||
private $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -101,6 +105,22 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository
|
||||
*/
|
||||
public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository)
|
||||
{
|
||||
$this->authCodeRepository = $authCodeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pathToPrivateKey
|
||||
*/
|
||||
@@ -118,7 +138,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setEmitter(EmitterInterface $emitter = null)
|
||||
{
|
||||
@@ -126,7 +146,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
||||
{
|
||||
@@ -134,61 +154,69 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return AuthCodeRepositoryInterface
|
||||
*/
|
||||
public function respondsWith()
|
||||
protected function getAuthCodeRepository()
|
||||
{
|
||||
return $this->respondsWith;
|
||||
return $this->authCodeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client
|
||||
* @return RefreshTokenRepositoryInterface
|
||||
*/
|
||||
protected function getRefreshTokenRepository()
|
||||
{
|
||||
return $this->refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param bool $validateSecret
|
||||
* @param bool $validateRedirectUri
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
protected function validateClient(
|
||||
ServerRequestInterface $request,
|
||||
$validateSecret = true,
|
||||
$validateRedirectUri = false
|
||||
) {
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
$clientId = $this->getRequestParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing');
|
||||
throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (!$client instanceof ClientEntityInterface) {
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
// If the client is confidential require the client secret
|
||||
$clientSecret = $this->getRequestParameter(
|
||||
'client_secret',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_PW', $request)
|
||||
);
|
||||
if (is_null($clientSecret) && $validateSecret === true) {
|
||||
throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing');
|
||||
|
||||
if ($client->canKeepASecret() && is_null($clientSecret)) {
|
||||
throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if (is_null($redirectUri) && $validateRedirectUri === true) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (!$client instanceof ClientEntityInterface) {
|
||||
if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) {
|
||||
$this->getEmitter()->emit(new Event('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
// If a redirect URI is provided ensure it matches what is pre-registered
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if ($redirectUri !== null && (strcmp($client->getRedirectUri(), $redirectUri) !== 0)) {
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
@@ -196,15 +224,15 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scopes in the request
|
||||
* Validate scopes in the request.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $redirectUri
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\ScopeEntity[]
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\ScopeEntity[]
|
||||
*/
|
||||
public function validateScopes(
|
||||
ServerRequestInterface $request,
|
||||
@@ -228,7 +256,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
);
|
||||
|
||||
if (($scope instanceof ScopeEntity) === false) {
|
||||
throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri);
|
||||
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
||||
}
|
||||
|
||||
$scopes[] = $scope;
|
||||
@@ -295,7 +323,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
* Issue an access token.
|
||||
*
|
||||
* @param \DateInterval $tokenTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
@@ -311,20 +339,27 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
array $scopes = []
|
||||
) {
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier(SecureKey::generate());
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if (is_string($scope)) {
|
||||
$s = new ScopeEntity();
|
||||
$s->setIdentifier($scope);
|
||||
$scope = $s;
|
||||
}
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an auth code
|
||||
* Issue an auth code.
|
||||
*
|
||||
* @param \DateInterval $tokenTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
@@ -332,8 +367,9 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
* @param string $redirectUri
|
||||
* @param array $scopes
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\AuthCodeEntity
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\AuthCodeEntity
|
||||
*/
|
||||
protected function issueAuthCode(
|
||||
\DateInterval $tokenTTL,
|
||||
@@ -343,7 +379,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
array $scopes = []
|
||||
) {
|
||||
$authCode = new AuthCodeEntity();
|
||||
$authCode->setIdentifier(SecureKey::generate());
|
||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||
$authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
@@ -353,6 +389,8 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$authCode->addScope($scope);
|
||||
}
|
||||
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
@@ -364,15 +402,42 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
protected function issueRefreshToken(AccessTokenEntity $accessToken)
|
||||
{
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier(SecureKey::generate());
|
||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
|
||||
return $refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Generate a new unique identifier.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateUniqueIdentifier($length = 40)
|
||||
{
|
||||
try {
|
||||
return bin2hex(random_bytes($length));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\TypeError $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Error $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Exception $e) {
|
||||
// If you get this message, the CSPRNG failed hard.
|
||||
throw OAuthServerException::serverError('Could not generate a random string');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user