Merge pull request #953 from Sephster/code-tidyup

Code Tidyup
This commit is contained in:
Andrew Millington 2018-10-13 17:06:21 +01:00 committed by GitHub
commit a34f5dd7db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 272 additions and 111 deletions

View File

@ -16,7 +16,8 @@
"zendframework/zend-diactoros": "^1.3.2", "zendframework/zend-diactoros": "^1.3.2",
"phpstan/phpstan": "^0.9.2", "phpstan/phpstan": "^0.9.2",
"phpstan/phpstan-phpunit": "^0.9.4", "phpstan/phpstan-phpunit": "^0.9.4",
"phpstan/phpstan-strict-rules": "^0.9.0" "phpstan/phpstan-strict-rules": "^0.9.0",
"roave/security-advisories": "dev-master"
}, },
"repositories": [ "repositories": [
{ {
@ -46,6 +47,12 @@
"email": "hello@alexbilbie.com", "email": "hello@alexbilbie.com",
"homepage": "http://www.alexbilbie.com", "homepage": "http://www.alexbilbie.com",
"role": "Developer" "role": "Developer"
},
{
"name": "Andy Millington",
"email": "andrew@noexceptions.io",
"homepage": "https://www.noexceptions.io",
"role": "Developer"
} }
], ],
"replace": { "replace": {

View File

@ -1,14 +1,13 @@
{ {
"require": { "require": {
"slim/slim": "3.0.*" "slim/slim": "^3.0.0"
}, },
"require-dev": { "require-dev": {
"league/event": "^2.1", "league/event": "^2.1",
"lcobucci/jwt": "^3.1", "lcobucci/jwt": "^3.2",
"paragonie/random_compat": "^2.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"defuse/php-encryption": "^2.1", "defuse/php-encryption": "^2.2",
"zendframework/zend-diactoros": "^1.0" "zendframework/zend-diactoros": "^2.0.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

219
examples/composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9813ed7c3b6dcf107f44df9392935b8f", "content-hash": "97f2878428e37d1d8e5418cc85cbfa3d",
"packages": [ "packages": [
{ {
"name": "container-interop/container-interop", "name": "container-interop/container-interop",
@ -39,21 +39,24 @@
}, },
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
"version": "v0.6.0", "version": "v1.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/FastRoute.git", "url": "https://github.com/nikic/FastRoute.git",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22" "reference": "181d480e08d9476e61381e04a71b34dc0432e812"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22", "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22", "reference": "181d480e08d9476e61381e04a71b34dc0432e812",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.4.0" "php": ">=5.4.0"
}, },
"require-dev": {
"phpunit/phpunit": "^4.8.35|~5.7"
},
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -78,29 +81,33 @@
"router", "router",
"routing" "routing"
], ],
"time": "2015-06-18T19:15:47+00:00" "time": "2018-02-13T20:26:39+00:00"
}, },
{ {
"name": "pimple/pimple", "name": "pimple/pimple",
"version": "v3.0.2", "version": "v3.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/silexphp/Pimple.git", "url": "https://github.com/silexphp/Pimple.git",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0",
"psr/container": "^1.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.0.x-dev" "dev-master": "3.2.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -124,7 +131,7 @@
"container", "container",
"dependency injection" "dependency injection"
], ],
"time": "2015-09-11T15:10:35+00:00" "time": "2018-01-21T07:42:36+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@ -227,27 +234,32 @@
}, },
{ {
"name": "slim/slim", "name": "slim/slim",
"version": "3.0.0", "version": "3.11.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim.git", "url": "https://github.com/slimphp/Slim.git",
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e" "reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/3b06f0f2d84dabbe81b6cea46ace46a3e883253e", "url": "https://api.github.com/repos/slimphp/Slim/zipball/d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e", "reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"container-interop/container-interop": "^1.1", "container-interop/container-interop": "^1.2",
"nikic/fast-route": "^0.6", "nikic/fast-route": "^1.0",
"php": ">=5.5.0", "php": ">=5.5.0",
"pimple/pimple": "^3.0", "pimple/pimple": "^3.0",
"psr/container": "^1.0",
"psr/http-message": "^1.0" "psr/http-message": "^1.0"
}, },
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.0" "phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.5"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -282,38 +294,38 @@
} }
], ],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"homepage": "http://slimframework.com", "homepage": "https://slimframework.com",
"keywords": [ "keywords": [
"api", "api",
"framework", "framework",
"micro", "micro",
"router" "router"
], ],
"time": "2015-12-07T14:11:09+00:00" "time": "2018-09-16T10:54:21+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
{ {
"name": "defuse/php-encryption", "name": "defuse/php-encryption",
"version": "v2.1.0", "version": "v2.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/defuse/php-encryption.git", "url": "https://github.com/defuse/php-encryption.git",
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689" "reference": "0f407c43b953d571421e0020ba92082ed5fb7620"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", "url": "https://api.github.com/repos/defuse/php-encryption/zipball/0f407c43b953d571421e0020ba92082ed5fb7620",
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", "reference": "0f407c43b953d571421e0020ba92082ed5fb7620",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-openssl": "*", "ext-openssl": "*",
"paragonie/random_compat": "~2.0", "paragonie/random_compat": ">= 2",
"php": ">=5.4.0" "php": ">=5.4.0"
}, },
"require-dev": { "require-dev": {
"nikic/php-parser": "^2.0|^3.0", "nikic/php-parser": "^2.0|^3.0|^4.0",
"phpunit/phpunit": "^4|^5" "phpunit/phpunit": "^4|^5"
}, },
"bin": [ "bin": [
@ -354,20 +366,20 @@
"security", "security",
"symmetric key cryptography" "symmetric key cryptography"
], ],
"time": "2017-05-18T21:28:48+00:00" "time": "2018-07-24T23:27:56+00:00"
}, },
{ {
"name": "lcobucci/jwt", "name": "lcobucci/jwt",
"version": "3.2.1", "version": "3.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/lcobucci/jwt.git", "url": "https://github.com/lcobucci/jwt.git",
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3" "reference": "c9704b751315d21735dc98d78d4f37bd73596da7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/ddce703826f9c5229781933b1a39069e38e6a0f3", "url": "https://api.github.com/repos/lcobucci/jwt/zipball/c9704b751315d21735dc98d78d4f37bd73596da7",
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3", "reference": "c9704b751315d21735dc98d78d4f37bd73596da7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -412,7 +424,7 @@
"JWS", "JWS",
"jwt" "jwt"
], ],
"time": "2016-10-31T20:09:32+00:00" "time": "2018-08-03T11:23:50+00:00"
}, },
{ {
"name": "league/event", "name": "league/event",
@ -466,33 +478,29 @@
}, },
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v2.0.10", "version": "v9.99.99",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paragonie/random_compat.git", "url": "https://github.com/paragonie/random_compat.git",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d" "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d", "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d", "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.2.0" "php": "^7"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "4.*|5.*" "phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^1"
}, },
"suggest": { "suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
}, },
"type": "library", "type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"MIT" "MIT"
@ -507,10 +515,129 @@
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [ "keywords": [
"csprng", "csprng",
"polyfill",
"pseudorandom", "pseudorandom",
"random" "random"
], ],
"time": "2017-03-13T16:27:32+00:00" "time": "2018-07-02T15:55:56+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"time": "2018-07-30T21:54:04+00:00"
},
{
"name": "zendframework/zend-diactoros",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-diactoros.git",
"reference": "0bae78192e634774b5584f0210c1232da82cb1ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/0bae78192e634774b5584f0210c1232da82cb1ff",
"reference": "0bae78192e634774b5584f0210c1232da82cb1ff",
"shasum": ""
},
"require": {
"php": "^7.1",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"ext-dom": "*",
"ext-libxml": "*",
"http-interop/http-factory-tests": "^0.5.0",
"php-http/psr7-integration-tests": "dev-master",
"phpunit/phpunit": "^7.0.2",
"zendframework/zend-coding-standard": "~1.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev",
"dev-develop": "2.1.x-dev",
"dev-release-1.8": "1.8.x-dev"
}
},
"autoload": {
"files": [
"src/functions/create_uploaded_file.php",
"src/functions/marshal_headers_from_sapi.php",
"src/functions/marshal_method_from_sapi.php",
"src/functions/marshal_protocol_version_from_sapi.php",
"src/functions/marshal_uri_from_sapi.php",
"src/functions/normalize_server.php",
"src/functions/normalize_uploaded_files.php",
"src/functions/parse_cookie_header.php"
],
"psr-4": {
"Zend\\Diactoros\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "PSR HTTP Message implementations",
"keywords": [
"http",
"psr",
"psr-7"
],
"time": "2018-09-27T19:49:04+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -18,7 +18,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface) public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
{ {
// Some logic to persist the refresh token in a database // Some logic to persist the refresh token in a database
} }

View File

@ -174,7 +174,7 @@ abstract class AbstractGrant implements GrantTypeInterface
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request); list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser); $clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
if (is_null($clientId)) { if ($clientId === null) {
throw OAuthServerException::invalidRequest('client_id'); throw OAuthServerException::invalidRequest('client_id');
} }
@ -217,13 +217,13 @@ abstract class AbstractGrant implements GrantTypeInterface
ClientEntityInterface $client, ClientEntityInterface $client,
ServerRequestInterface $request ServerRequestInterface $request
) { ) {
if (is_string($client->getRedirectUri()) if (\is_string($client->getRedirectUri())
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0) && (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
) { ) {
$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()) } elseif (\is_array($client->getRedirectUri())
&& in_array($redirectUri, $client->getRedirectUri(), true) === 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();
@ -233,8 +233,8 @@ abstract class AbstractGrant implements GrantTypeInterface
/** /**
* Validate scopes in the request. * Validate scopes in the request.
* *
* @param string $scopes * @param string|array $scopes
* @param string $redirectUri * @param string $redirectUri
* *
* @throws OAuthServerException * @throws OAuthServerException
* *
@ -242,13 +242,13 @@ abstract class AbstractGrant implements GrantTypeInterface
*/ */
public function validateScopes($scopes, $redirectUri = null) public function validateScopes($scopes, $redirectUri = null)
{ {
$scopesList = array_filter(explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), function ($scope) { if (!\is_array($scopes)) {
return !empty($scope); $scopes = $this->convertScopesQueryStringToArray($scopes);
}); }
$validScopes = []; $validScopes = [];
foreach ($scopesList as $scopeItem) { foreach ($scopes as $scopeItem) {
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem); $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
if ($scope instanceof ScopeEntityInterface === false) { if ($scope instanceof ScopeEntityInterface === false) {
@ -261,6 +261,20 @@ abstract class AbstractGrant implements GrantTypeInterface
return $validScopes; return $validScopes;
} }
/**
* Converts a scopes query string to an array to easily iterate for validation.
*
* @param string $scopes
*
* @return array
*/
private function convertScopesQueryStringToArray($scopes)
{
return array_filter(explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), function ($scope) {
return !empty($scope);
});
}
/** /**
* Retrieve request parameter. * Retrieve request parameter.
* *
@ -274,7 +288,7 @@ abstract class AbstractGrant implements GrantTypeInterface
{ {
$requestParameters = (array) $request->getParsedBody(); $requestParameters = (array) $request->getParsedBody();
return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default; return $requestParameters[$parameter] ?? $default;
} }
/** /**

View File

@ -10,7 +10,6 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Entities\UserEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
@ -37,6 +36,8 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
* @param AuthCodeRepositoryInterface $authCodeRepository * @param AuthCodeRepositoryInterface $authCodeRepository
* @param RefreshTokenRepositoryInterface $refreshTokenRepository * @param RefreshTokenRepositoryInterface $refreshTokenRepository
* @param \DateInterval $authCodeTTL * @param \DateInterval $authCodeTTL
*
* @throws \Exception
*/ */
public function __construct( public function __construct(
AuthCodeRepositoryInterface $authCodeRepository, AuthCodeRepositoryInterface $authCodeRepository,
@ -78,47 +79,13 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
throw OAuthServerException::invalidRequest('code'); throw OAuthServerException::invalidRequest('code');
} }
// Validate the authorization code
try { try {
$authCodePayload = json_decode($this->decrypt($encryptedAuthCode)); $authCodePayload = json_decode($this->decrypt($encryptedAuthCode));
if (time() > $authCodePayload->expire_time) {
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
}
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { $this->validateAuthorizationCode($authCodePayload, $client, $request);
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
}
if ($authCodePayload->client_id !== $client->getIdentifier()) {
throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
}
// The redirect URI is required in this request
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) {
throw OAuthServerException::invalidRequest('redirect_uri');
}
if ($authCodePayload->redirect_uri !== $redirectUri) {
throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
}
$scopes = [];
foreach ($authCodePayload->scopes as $scopeId) {
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
if ($scope instanceof ScopeEntityInterface === false) {
// @codeCoverageIgnoreStart
throw OAuthServerException::invalidScope($scopeId);
// @codeCoverageIgnoreEnd
}
$scopes[] = $scope;
}
// Finalize the requested scopes
$scopes = $this->scopeRepository->finalizeScopes( $scopes = $this->scopeRepository->finalizeScopes(
$scopes, $this->validateScopes($authCodePayload->scopes),
$this->getIdentifier(), $this->getIdentifier(),
$client, $client,
$authCodePayload->user_id $authCodePayload->user_id
@ -130,6 +97,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
// Validate code challenge // Validate code challenge
if ($this->enableCodeExchangeProof === true) { if ($this->enableCodeExchangeProof === true) {
$codeVerifier = $this->getRequestParameter('code_verifier', $request, null); $codeVerifier = $this->getRequestParameter('code_verifier', $request, null);
if ($codeVerifier === null) { if ($codeVerifier === null) {
throw OAuthServerException::invalidRequest('code_verifier'); throw OAuthServerException::invalidRequest('code_verifier');
} }
@ -190,6 +158,41 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
return $responseType; return $responseType;
} }
/**
* Validate the authorization code.
*
* @param \stdClass $authCodePayload
* @param ClientEntityInterface $client
* @param ServerRequestInterface $request
*/
private function validateAuthorizationCode(
$authCodePayload,
ClientEntityInterface $client,
ServerRequestInterface $request
) {
if (time() > $authCodePayload->expire_time) {
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
}
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
}
if ($authCodePayload->client_id !== $client->getIdentifier()) {
throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
}
// The redirect URI is required in this request
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) {
throw OAuthServerException::invalidRequest('redirect_uri');
}
if ($authCodePayload->redirect_uri !== $redirectUri) {
throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
}
}
/** /**
* Return the grant identifier that can be used in matching up requests. * Return the grant identifier that can be used in matching up requests.
* *
@ -223,7 +226,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
$this->getServerParameter('PHP_AUTH_USER', $request) $this->getServerParameter('PHP_AUTH_USER', $request)
); );
if (is_null($clientId)) { if ($clientId === null) {
throw OAuthServerException::invalidRequest('client_id'); throw OAuthServerException::invalidRequest('client_id');
} }
@ -243,12 +246,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
if ($redirectUri !== null) { if ($redirectUri !== null) {
$this->validateRedirectUri($redirectUri, $client, $request); $this->validateRedirectUri($redirectUri, $client, $request);
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1 } elseif (empty($client->getRedirectUri()) ||
|| empty($client->getRedirectUri())) { (\is_array($client->getRedirectUri()) && \count($client->getRedirectUri()) !== 1)) {
$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 { } else {
$redirectUri = is_array($client->getRedirectUri()) $redirectUri = \is_array($client->getRedirectUri())
? $client->getRedirectUri()[0] ? $client->getRedirectUri()[0]
: $client->getRedirectUri(); : $client->getRedirectUri();
} }
@ -279,7 +282,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'], true) === 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`'
@ -311,11 +314,8 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest'); throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest');
} }
$finalRedirectUri = ($authorizationRequest->getRedirectUri() === null) $finalRedirectUri = $authorizationRequest->getRedirectUri()
? is_array($authorizationRequest->getClient()->getRedirectUri()) ?? $this->getClientRedirectUri($authorizationRequest);
? $authorizationRequest->getClient()->getRedirectUri()[0]
: $authorizationRequest->getClient()->getRedirectUri()
: $authorizationRequest->getRedirectUri();
// The user approved the client, redirect them back with an auth code // The user approved the client, redirect them back with an auth code
if ($authorizationRequest->isAuthorizationApproved() === true) { if ($authorizationRequest->isAuthorizationApproved() === true) {
@ -367,4 +367,18 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
) )
); );
} }
/**
* Get the client redirect URI if not set in the request.
*
* @param AuthorizationRequest $authorizationRequest
*
* @return string
*/
private function getClientRedirectUri(AuthorizationRequest $authorizationRequest)
{
return \is_array($authorizationRequest->getClient()->getRedirectUri())
? $authorizationRequest->getClient()->getRedirectUri()[0]
: $authorizationRequest->getClient()->getRedirectUri();
}
} }