mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-11-10 07:22:11 +05:30
Merge branch 'master' of https://github.com/thephpleague/oauth2-server into fix-pkce-implementation
This commit is contained in:
commit
e0cc5ee1b0
10
.travis.yml
10
.travis.yml
@ -5,19 +5,23 @@ sudo: false
|
|||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- vendor
|
- vendor
|
||||||
|
|
||||||
|
env:
|
||||||
|
- DEPENDENCIES=""
|
||||||
|
- DEPENDENCIES="--prefer-lowest --prefer-stable"
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.6
|
|
||||||
- 7.0
|
- 7.0
|
||||||
- 7.1
|
- 7.1
|
||||||
- 7.2
|
- 7.2
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- travis_retry composer install --no-interaction --prefer-source
|
- composer update --no-interaction --prefer-dist $DEPENDENCIES
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- vendor/bin/phpunit
|
- vendor/bin/phpunit
|
||||||
|
- vendor/bin/phpstan analyse -l 6 -c phpstan.neon src tests
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
@ -4,17 +4,20 @@
|
|||||||
"homepage": "https://oauth2.thephpleague.com/",
|
"homepage": "https://oauth2.thephpleague.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.6.0",
|
"php": ">=7.0.0",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"league/event": "^2.1",
|
"league/event": "^2.1",
|
||||||
"lcobucci/jwt": "^3.1",
|
"lcobucci/jwt": "^3.2.2",
|
||||||
"paragonie/random_compat": "^2.0",
|
"paragonie/random_compat": "^2.0",
|
||||||
"psr/http-message": "^1.0",
|
"psr/http-message": "^1.0.1",
|
||||||
"defuse/php-encryption": "^2.1"
|
"defuse/php-encryption": "^2.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^4.8.38 || ^5.7.21",
|
"phpunit/phpunit": "^6.3 || ^7.0",
|
||||||
"zendframework/zend-diactoros": "^1.0"
|
"zendframework/zend-diactoros": "^1.3.2",
|
||||||
|
"phpstan/phpstan": "^0.9.2",
|
||||||
|
"phpstan/phpstan-phpunit": "^0.9.4",
|
||||||
|
"phpstan/phpstan-strict-rules": "^0.9.0"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
|
@ -49,16 +49,18 @@ $app->get(
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$totalUsers = count($users);
|
||||||
|
|
||||||
// If the access token doesn't have the `basic` scope hide users' names
|
// If the access token doesn't have the `basic` scope hide users' names
|
||||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < $totalUsers; $i++) {
|
||||||
unset($users[$i]['name']);
|
unset($users[$i]['name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the access token doesn't have the `email` scope hide users' email addresses
|
// If the access token doesn't have the `email` scope hide users' email addresses
|
||||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < $totalUsers; $i++) {
|
||||||
unset($users[$i]['email']);
|
unset($users[$i]['email']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ $app = new App([
|
|||||||
$privateKeyPath,
|
$privateKeyPath,
|
||||||
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
|
||||||
|
|
||||||
// Enable the implicit grant on the server with a token TTL of 1 hour
|
// Enable the implicit grant on the server with a token TTL of 1 hour
|
||||||
$server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H')));
|
$server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H')));
|
||||||
|
5
phpstan.neon
Normal file
5
phpstan.neon
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
includes:
|
||||||
|
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||||
|
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||||
|
- vendor/phpstan/phpstan-phpunit/strictRules.neon
|
||||||
|
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
@ -17,6 +17,7 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
|||||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||||
|
use League\OAuth2\Server\ResponseTypes\AbstractResponseType;
|
||||||
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
||||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
@ -190,7 +191,6 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
if ($tokenResponse instanceof ResponseTypeInterface) {
|
if ($tokenResponse instanceof ResponseTypeInterface) {
|
||||||
return $tokenResponse->generateHttpResponse($response);
|
return $tokenResponse->generateHttpResponse($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw OAuthServerException::unsupportedGrantType();
|
throw OAuthServerException::unsupportedGrantType();
|
||||||
@ -207,7 +207,9 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
$this->responseType = new BearerTokenResponse();
|
$this->responseType = new BearerTokenResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->responseType->setPrivateKey($this->privateKey);
|
if ($this->responseType instanceof AbstractResponseType === true) {
|
||||||
|
$this->responseType->setPrivateKey($this->privateKey);
|
||||||
|
}
|
||||||
$this->responseType->setEncryptionKey($this->encryptionKey);
|
$this->responseType->setEncryptionKey($this->encryptionKey);
|
||||||
|
|
||||||
return $this->responseType;
|
return $this->responseType;
|
||||||
|
@ -48,9 +48,9 @@ class CryptKey
|
|||||||
if ($keyPermissionsCheck === true) {
|
if ($keyPermissionsCheck === true) {
|
||||||
// Verify the permissions of the key
|
// Verify the permissions of the key
|
||||||
$keyPathPerms = decoct(fileperms($keyPath) & 0777);
|
$keyPathPerms = decoct(fileperms($keyPath) & 0777);
|
||||||
if (in_array($keyPathPerms, ['600', '660'], true) === false) {
|
if (in_array($keyPathPerms, ['400', '440', '600', '660'], true) === false) {
|
||||||
trigger_error(sprintf(
|
trigger_error(sprintf(
|
||||||
'Key file "%s" permissions are not correct, should be 600 or 660 instead of %s',
|
'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
|
||||||
$keyPath,
|
$keyPath,
|
||||||
$keyPathPerms
|
$keyPathPerms
|
||||||
), E_USER_NOTICE);
|
), E_USER_NOTICE);
|
||||||
@ -73,7 +73,11 @@ class CryptKey
|
|||||||
$tmpDir = sys_get_temp_dir();
|
$tmpDir = sys_get_temp_dir();
|
||||||
$keyPath = $tmpDir . '/' . sha1($key) . '.key';
|
$keyPath = $tmpDir . '/' . sha1($key) . '.key';
|
||||||
|
|
||||||
if (!file_exists($keyPath) && !touch($keyPath)) {
|
if (file_exists($keyPath)) {
|
||||||
|
return 'file://' . $keyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!touch($keyPath)) {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
throw new \RuntimeException(sprintf('"%s" key file could not be created', $keyPath));
|
throw new \RuntimeException(sprintf('"%s" key file could not be created', $keyPath));
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Entities;
|
namespace League\OAuth2\Server\Entities;
|
||||||
|
|
||||||
|
use Lcobucci\JWT\Token;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
|
||||||
interface AccessTokenEntityInterface extends TokenInterface
|
interface AccessTokenEntityInterface extends TokenInterface
|
||||||
@ -18,7 +19,7 @@ interface AccessTokenEntityInterface extends TokenInterface
|
|||||||
*
|
*
|
||||||
* @param CryptKey $privateKey
|
* @param CryptKey $privateKey
|
||||||
*
|
*
|
||||||
* @return string
|
* @return Token
|
||||||
*/
|
*/
|
||||||
public function convertToJWT(CryptKey $privateKey);
|
public function convertToJWT(CryptKey $privateKey);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ interface RefreshTokenEntityInterface
|
|||||||
/**
|
/**
|
||||||
* Set the token's identifier.
|
* Set the token's identifier.
|
||||||
*
|
*
|
||||||
* @param $identifier
|
* @param mixed $identifier
|
||||||
*/
|
*/
|
||||||
public function setIdentifier($identifier);
|
public function setIdentifier($identifier);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ interface TokenInterface
|
|||||||
/**
|
/**
|
||||||
* Set the token's identifier.
|
* Set the token's identifier.
|
||||||
*
|
*
|
||||||
* @param $identifier
|
* @param mixed $identifier
|
||||||
*/
|
*/
|
||||||
public function setIdentifier($identifier);
|
public function setIdentifier($identifier);
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ interface TokenInterface
|
|||||||
/**
|
/**
|
||||||
* Set the identifier of the user associated with the token.
|
* Set the identifier of the user associated with the token.
|
||||||
*
|
*
|
||||||
* @param string|int $identifier The identifier of the user
|
* @param string|int|null $identifier The identifier of the user
|
||||||
*/
|
*/
|
||||||
public function setUserIdentifier($identifier);
|
public function setUserIdentifier($identifier);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the token user's identifier.
|
* Get the token user's identifier.
|
||||||
*
|
*
|
||||||
* @return string|int
|
* @return string|int|null
|
||||||
*/
|
*/
|
||||||
public function getUserIdentifier();
|
public function getUserIdentifier();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Entities\Traits;
|
|||||||
use Lcobucci\JWT\Builder;
|
use Lcobucci\JWT\Builder;
|
||||||
use Lcobucci\JWT\Signer\Key;
|
use Lcobucci\JWT\Signer\Key;
|
||||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||||
|
use Lcobucci\JWT\Token;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
@ -23,7 +24,7 @@ trait AccessTokenTrait
|
|||||||
*
|
*
|
||||||
* @param CryptKey $privateKey
|
* @param CryptKey $privateKey
|
||||||
*
|
*
|
||||||
* @return string
|
* @return Token
|
||||||
*/
|
*/
|
||||||
public function convertToJWT(CryptKey $privateKey)
|
public function convertToJWT(CryptKey $privateKey)
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ namespace League\OAuth2\Server\Entities\Traits;
|
|||||||
|
|
||||||
trait EntityTrait
|
trait EntityTrait
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $identifier;
|
protected $identifier;
|
||||||
|
@ -25,7 +25,7 @@ trait TokenEntityTrait
|
|||||||
protected $expiryDateTime;
|
protected $expiryDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|int
|
* @var string|int|null
|
||||||
*/
|
*/
|
||||||
protected $userIdentifier;
|
protected $userIdentifier;
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ trait TokenEntityTrait
|
|||||||
/**
|
/**
|
||||||
* Set the identifier of the user associated with the token.
|
* Set the identifier of the user associated with the token.
|
||||||
*
|
*
|
||||||
* @param string|int $identifier The identifier of the user
|
* @param string|int|null $identifier The identifier of the user
|
||||||
*/
|
*/
|
||||||
public function setUserIdentifier($identifier)
|
public function setUserIdentifier($identifier)
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@ trait TokenEntityTrait
|
|||||||
/**
|
/**
|
||||||
* Get the token user's identifier.
|
* Get the token user's identifier.
|
||||||
*
|
*
|
||||||
* @return string|int
|
* @return string|int|null
|
||||||
*/
|
*/
|
||||||
public function getUserIdentifier()
|
public function getUserIdentifier()
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,11 @@ class OAuthServerException extends \Exception
|
|||||||
*/
|
*/
|
||||||
private $redirectUri;
|
private $redirectUri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $payload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw a new exception.
|
* Throw a new exception.
|
||||||
*
|
*
|
||||||
@ -50,6 +55,33 @@ class OAuthServerException extends \Exception
|
|||||||
$this->errorType = $errorType;
|
$this->errorType = $errorType;
|
||||||
$this->hint = $hint;
|
$this->hint = $hint;
|
||||||
$this->redirectUri = $redirectUri;
|
$this->redirectUri = $redirectUri;
|
||||||
|
$this->payload = [
|
||||||
|
'error' => $errorType,
|
||||||
|
'message' => $message,
|
||||||
|
];
|
||||||
|
if ($hint !== null) {
|
||||||
|
$this->payload['hint'] = $hint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current payload.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPayload()
|
||||||
|
{
|
||||||
|
return $this->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current payload.
|
||||||
|
*
|
||||||
|
* @param array $payload
|
||||||
|
*/
|
||||||
|
public function setPayload(array $payload)
|
||||||
|
{
|
||||||
|
$this->payload = $payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +163,7 @@ class OAuthServerException extends \Exception
|
|||||||
/**
|
/**
|
||||||
* Server error.
|
* Server error.
|
||||||
*
|
*
|
||||||
* @param $hint
|
* @param string $hint
|
||||||
*
|
*
|
||||||
* @return static
|
* @return static
|
||||||
*
|
*
|
||||||
@ -213,21 +245,15 @@ class OAuthServerException extends \Exception
|
|||||||
*
|
*
|
||||||
* @param ResponseInterface $response
|
* @param ResponseInterface $response
|
||||||
* @param bool $useFragment True if errors should be in the URI fragment instead of query string
|
* @param bool $useFragment True if errors should be in the URI fragment instead of query string
|
||||||
|
* @param int $jsonOptions options passed to json_encode
|
||||||
*
|
*
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function generateHttpResponse(ResponseInterface $response, $useFragment = false)
|
public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
|
||||||
{
|
{
|
||||||
$headers = $this->getHttpHeaders();
|
$headers = $this->getHttpHeaders();
|
||||||
|
|
||||||
$payload = [
|
$payload = $this->getPayload();
|
||||||
'error' => $this->getErrorType(),
|
|
||||||
'message' => $this->getMessage(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->hint !== null) {
|
|
||||||
$payload['hint'] = $this->hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->redirectUri !== null) {
|
if ($this->redirectUri !== null) {
|
||||||
if ($useFragment === true) {
|
if ($useFragment === true) {
|
||||||
@ -243,7 +269,7 @@ class OAuthServerException extends \Exception
|
|||||||
$response = $response->withHeader($header, $content);
|
$response = $response->withHeader($header, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->getBody()->write(json_encode($payload));
|
$response->getBody()->write(json_encode($payload, $jsonOptions));
|
||||||
|
|
||||||
return $response->withStatus($this->getHttpStatusCode());
|
return $response->withStatus($this->getHttpStatusCode());
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
@ -341,7 +341,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
*
|
*
|
||||||
* @param \DateInterval $accessTokenTTL
|
* @param \DateInterval $accessTokenTTL
|
||||||
* @param ClientEntityInterface $client
|
* @param ClientEntityInterface $client
|
||||||
* @param string $userIdentifier
|
* @param string|null $userIdentifier
|
||||||
* @param ScopeEntityInterface[] $scopes
|
* @param ScopeEntityInterface[] $scopes
|
||||||
*
|
*
|
||||||
* @throws OAuthServerException
|
* @throws OAuthServerException
|
||||||
|
@ -244,23 +244,24 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
||||||
|| empty($client->getRedirectUri())
|
|| empty($client->getRedirectUri())) {
|
||||||
) {
|
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
|
} else {
|
||||||
|
$redirectUri = is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
||||||
is_array($client->getRedirectUri())
|
$redirectUri
|
||||||
? $client->getRedirectUri()[0]
|
|
||||||
: $client->getRedirectUri()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||||
@ -279,7 +280,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
}
|
}
|
||||||
|
|
||||||
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
||||||
if (in_array($codeChallengeMethod, ['plain', 'S256']) === false) {
|
if (in_array($codeChallengeMethod, ['plain', 'S256'], true) === false) {
|
||||||
throw OAuthServerException::invalidRequest(
|
throw OAuthServerException::invalidRequest(
|
||||||
'code_challenge_method',
|
'code_challenge_method',
|
||||||
'Code challenge method must be `plain` or `S256`'
|
'Code challenge method must be `plain` or `S256`'
|
||||||
|
@ -33,7 +33,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \DateInterval $accessTokenTTL
|
* @param \DateInterval $accessTokenTTL
|
||||||
* @param string $queryDelimiter
|
* @param string $queryDelimiter
|
||||||
*/
|
*/
|
||||||
public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#')
|
public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#')
|
||||||
{
|
{
|
||||||
@ -144,23 +144,24 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
||||||
|| empty($client->getRedirectUri())
|
|| empty($client->getRedirectUri())) {
|
||||||
) {
|
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
|
} else {
|
||||||
|
$redirectUri = is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
||||||
is_array($client->getRedirectUri())
|
$redirectUri
|
||||||
? $client->getRedirectUri()[0]
|
|
||||||
: $client->getRedirectUri()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Grant;
|
namespace League\OAuth2\Server\Grant;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\RequestEvent;
|
use League\OAuth2\Server\RequestEvent;
|
||||||
@ -53,7 +52,7 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
||||||
// the request doesn't include any new scopes
|
// the request doesn't include any new scopes
|
||||||
foreach ($scopes as $scope) {
|
foreach ($scopes as $scope) {
|
||||||
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) {
|
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes'], true) === false) {
|
||||||
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,12 @@ interface ClientRepositoryInterface extends RepositoryInterface
|
|||||||
* Get a client.
|
* Get a client.
|
||||||
*
|
*
|
||||||
* @param string $clientIdentifier The client's identifier
|
* @param string $clientIdentifier The client's identifier
|
||||||
* @param string $grantType The grant type used
|
* @param null|string $grantType The grant type used (if sent)
|
||||||
* @param null|string $clientSecret The client's secret (if sent)
|
* @param null|string $clientSecret The client's secret (if sent)
|
||||||
* @param bool $mustValidateSecret If true the client must attempt to validate the secret if the client
|
* @param bool $mustValidateSecret If true the client must attempt to validate the secret if the client
|
||||||
* is confidential
|
* is confidential
|
||||||
*
|
*
|
||||||
* @return ClientEntityInterface
|
* @return ClientEntityInterface
|
||||||
*/
|
*/
|
||||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true);
|
public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class AuthorizationRequest
|
|||||||
/**
|
/**
|
||||||
* The redirect URI used in the request
|
* The redirect URI used in the request
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string|null
|
||||||
*/
|
*/
|
||||||
protected $redirectUri;
|
protected $redirectUri;
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ class AuthorizationRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getRedirectUri()
|
public function getRedirectUri()
|
||||||
{
|
{
|
||||||
@ -167,7 +167,7 @@ class AuthorizationRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $redirectUri
|
* @param string|null $redirectUri
|
||||||
*/
|
*/
|
||||||
public function setRedirectUri($redirectUri)
|
public function setRedirectUri($redirectUri)
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,9 @@ class ResourceServer
|
|||||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->authorizationValidator->setPublicKey($this->publicKey);
|
if ($this->authorizationValidator instanceof BearerTokenValidator === true) {
|
||||||
|
$this->authorizationValidator->setPublicKey($this->publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->authorizationValidator;
|
return $this->authorizationValidator;
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,14 @@ use LeagueTests\Stubs\ClientEntity;
|
|||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
use Zend\Diactoros\ServerRequestFactory;
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
|
||||||
class AuthorizationServerTest extends TestCase
|
class AuthorizationServerTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
const DEFAULT_SCOPE = 'basic';
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
@ -198,16 +197,16 @@ class AuthorizationServerTest extends TestCase
|
|||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
$clientRepositoryMock,
|
$clientRepositoryMock,
|
||||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
||||||
$this->getMock(ScopeRepositoryInterface::class),
|
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
||||||
'file://' . __DIR__ . '/Stubs/private.key',
|
'file://' . __DIR__ . '/Stubs/private.key',
|
||||||
'file://' . __DIR__ . '/Stubs/public.key'
|
'file://' . __DIR__ . '/Stubs/public.key'
|
||||||
);
|
);
|
||||||
|
@ -20,9 +20,7 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testGenerateHttpResponse()
|
public function testGenerateHttpResponse()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
@ -64,9 +62,7 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
|
|
||||||
public function testGenerateHttpResponseWithExtraParams()
|
public function testGenerateHttpResponseWithExtraParams()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponseWithParams();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponseWithParams($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
@ -111,10 +107,7 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
|
|
||||||
public function testDetermineAccessTokenInHeaderValidToken()
|
public function testDetermineAccessTokenInHeaderValidToken()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
@ -158,9 +151,8 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
public function testDetermineAccessTokenInHeaderInvalidJWT()
|
public function testDetermineAccessTokenInHeaderInvalidJWT()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
$responseType = new BearerTokenResponse();
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
@ -247,9 +239,7 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
|
|
||||||
public function testDetermineAccessTokenInHeaderInvalidToken()
|
public function testDetermineAccessTokenInHeaderInvalidToken()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
@ -273,9 +263,7 @@ class BearerResponseTypeTest extends TestCase
|
|||||||
|
|
||||||
public function testDetermineMissingBearerInHeader()
|
public function testDetermineMissingBearerInHeader()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class CryptKeyTest extends TestCase
|
|||||||
|
|
||||||
public function testKeyCreation()
|
public function testKeyCreation()
|
||||||
{
|
{
|
||||||
$keyFile = __DIR__ . '/Stubs/public.key';
|
$keyFile = __DIR__ . '/../Stubs/public.key';
|
||||||
$key = new CryptKey($keyFile, 'secret');
|
$key = new CryptKey($keyFile, 'secret');
|
||||||
|
|
||||||
$this->assertEquals('file://' . $keyFile, $key->getKeyPath());
|
$this->assertEquals('file://' . $keyFile, $key->getKeyPath());
|
||||||
@ -26,7 +26,7 @@ class CryptKeyTest extends TestCase
|
|||||||
|
|
||||||
public function testKeyFileCreation()
|
public function testKeyFileCreation()
|
||||||
{
|
{
|
||||||
$keyContent = file_get_contents(__DIR__ . '/Stubs/public.key');
|
$keyContent = file_get_contents(__DIR__ . '/../Stubs/public.key');
|
||||||
$key = new CryptKey($keyContent);
|
$key = new CryptKey($keyContent);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -34,7 +34,7 @@ class CryptKeyTest extends TestCase
|
|||||||
$key->getKeyPath()
|
$key->getKeyPath()
|
||||||
);
|
);
|
||||||
|
|
||||||
$keyContent = file_get_contents(__DIR__ . '/Stubs/private.key.crlf');
|
$keyContent = file_get_contents(__DIR__ . '/../Stubs/private.key.crlf');
|
||||||
$key = new CryptKey($keyContent);
|
$key = new CryptKey($keyContent);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
Loading…
Reference in New Issue
Block a user