mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-11-22 21:23:02 +05:30
commit
1a3107b4fc
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ phpunit.xml
|
||||
examples/public.key
|
||||
examples/private.key
|
||||
build
|
||||
*.orig
|
||||
|
@ -12,7 +12,6 @@ env:
|
||||
- DEPENDENCIES="--prefer-lowest --prefer-stable"
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
@ -31,3 +30,4 @@ after_script:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- 8.0.0
|
||||
|
21
CHANGELOG.md
21
CHANGELOG.md
@ -6,6 +6,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Flag, `requireCodeChallengeForPublicClients`, used to reject public clients that do not provide a code challenge for the Auth Code Grant; use AuthCodeGrant::disableRequireCodeCallengeForPublicClients() to turn off this requirement (PR #938)
|
||||
- Public clients can now use the Auth Code Grant (PR #938)
|
||||
- `isConfidential` getter added to `ClientEntity` to identify type of client (PR #938)
|
||||
- Function `validateClient()` added to validate clients which was previously performed by the `getClientEntity()` function (PR #938)
|
||||
- Add a new function to the AbstractGrant class called `getClientEntityOrFail()`. This is a wrapper around the `getClientEntity()` function that ensures we emit and throw an exception if the repo doesn't return a client entity. (PR #1010)
|
||||
|
||||
### Changed
|
||||
- Replace `convertToJWT()` interface with a more generic `__toString()` to improve extensibility; AccessTokenEntityInterface now requires `setPrivateKey(CryptKey $privateKey)` so `__toString()` has everything it needs to work (PR #874)
|
||||
- The `invalidClient()` function accepts a PSR-7 compliant `$serverRequest` argument to avoid accessing the `$_SERVER` global variable and improve testing (PR #899)
|
||||
- `issueAccessToken()` in the Abstract Grant no longer sets access token client, user ID or scopes. These values should already have been set when calling `getNewToken()` (PR #919)
|
||||
- No longer need to enable PKCE with `enableCodeExchangeProof` flag. Any client sending a code challenge will initiate PKCE checks. (PR #938)
|
||||
- Function `getClientEntity()` no longer performs client validation (PR #938)
|
||||
- Password Grant now returns an invalid_grant error instead of invalid_credentials if a user cannot be validated (PR #967)
|
||||
- Use `DateTimeImmutable()` instead of `DateTime()`, `time()` instead of `(new DateTime())->getTimeStamp()`, and `DateTime::getTimeStamp()` instead of `DateTime::format('U')` (PR #963)
|
||||
|
||||
### Removed
|
||||
- `enableCodeExchangeProof` flag (PR #938)
|
||||
- Support for PHP 7.0 (PR #1014)
|
||||
- Remove JTI claim from JWT header (PR #1031)
|
||||
|
||||
## [7.4.0] - released 2019-05-05
|
||||
|
||||
### Changed
|
||||
|
11
README.md
11
README.md
@ -31,12 +31,11 @@ This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](ht
|
||||
|
||||
The following versions of PHP are supported:
|
||||
|
||||
* PHP 7.0
|
||||
* PHP 7.1
|
||||
* PHP 7.2
|
||||
* PHP 7.3
|
||||
|
||||
The `openssl` extension is also required.
|
||||
The `openssl` and `json` extensions are also required.
|
||||
|
||||
All HTTP messages passed to the server should be [PSR-7 compliant](https://www.php-fig.org/psr/psr-7/). This ensures interoperability with other packages and frameworks.
|
||||
|
||||
@ -86,13 +85,9 @@ Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague
|
||||
|
||||
If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below.
|
||||
|
||||
## Commercial Support
|
||||
|
||||
If you would like help implementing this library into your existing platform, or would be interested in OAuth advice or training for you and your team please get in touch with [Glynde Labs](https://glyndelabs.com).
|
||||
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email `hello@alexbilbie.com` instead of using the issue tracker.
|
||||
If you discover any security related issues, please email `andrew@noexceptions.io` instead of using the issue tracker.
|
||||
|
||||
## License
|
||||
|
||||
@ -100,7 +95,7 @@ This package is released under the MIT License. See the bundled [LICENSE](https:
|
||||
|
||||
## Credits
|
||||
|
||||
This code is principally developed and maintained by [Andy Millington](https://twitter.com/Sephster) and [Simon Hamp](https://twitter.com/simonhamp).
|
||||
This code is principally developed and maintained by [Andy Millington](https://twitter.com/Sephster).
|
||||
|
||||
Between 2012 and 2017 this library was developed and maintained by [Alex Bilbie](https://alexbilbie.com/).
|
||||
|
||||
|
@ -4,19 +4,19 @@
|
||||
"homepage": "https://oauth2.thephpleague.com/",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"php": ">=7.1.0",
|
||||
"ext-openssl": "*",
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.2.2",
|
||||
"league/event": "^2.2",
|
||||
"lcobucci/jwt": "^3.3.1",
|
||||
"psr/http-message": "^1.0.1",
|
||||
"defuse/php-encryption": "^2.1"
|
||||
"defuse/php-encryption": "^2.2.1",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.3 || ^7.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",
|
||||
"phpunit/phpunit": "^7.5.13 || ^8.2.3",
|
||||
"zendframework/zend-diactoros": "^2.1.2",
|
||||
"phpstan/phpstan": "^0.11.8",
|
||||
"phpstan/phpstan-phpunit": "^0.11.2",
|
||||
"roave/security-advisories": "dev-master"
|
||||
},
|
||||
"repositories": [
|
||||
|
@ -3,11 +3,11 @@
|
||||
"slim/slim": "^3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.2",
|
||||
"league/event": "^2.2",
|
||||
"lcobucci/jwt": "^3.3",
|
||||
"psr/http-message": "^1.0",
|
||||
"defuse/php-encryption": "^2.2",
|
||||
"zendframework/zend-diactoros": "^2.0.0"
|
||||
"zendframework/zend-diactoros": "^2.1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
69
examples/composer.lock
generated
69
examples/composer.lock
generated
@ -1,10 +1,10 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"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#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "97f2878428e37d1d8e5418cc85cbfa3d",
|
||||
"content-hash": "a7f5c3fdcadb17399bbd97f15e1b11f1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
@ -234,16 +234,16 @@
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "3.11.0",
|
||||
"version": "3.12.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a"
|
||||
"reference": "eaee12ef8d0750db62b8c548016d82fb33addb6b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
|
||||
"reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/eaee12ef8d0750db62b8c548016d82fb33addb6b",
|
||||
"reference": "eaee12ef8d0750db62b8c548016d82fb33addb6b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -301,7 +301,7 @@
|
||||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2018-09-16T10:54:21+00:00"
|
||||
"time": "2019-04-16T16:47:29+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@ -370,33 +370,30 @@
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "3.2.4",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "c9704b751315d21735dc98d78d4f37bd73596da7"
|
||||
"reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/c9704b751315d21735dc98d78d4f37bd73596da7",
|
||||
"reference": "c9704b751315d21735dc98d78d4f37bd73596da7",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/a11ec5f4b4d75d1fcd04e133dede4c317aac9e18",
|
||||
"reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=5.5"
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mdanter/ecc": "~0.3.1",
|
||||
"mikey179/vfsstream": "~1.5",
|
||||
"phpmd/phpmd": "~2.2",
|
||||
"phpunit/php-invoker": "~1.1",
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"phpunit/phpunit": "^5.7 || ^7.3",
|
||||
"squizlabs/php_codesniffer": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"mdanter/ecc": "Required to use Elliptic Curves based algorithms."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@ -424,20 +421,20 @@
|
||||
"JWS",
|
||||
"jwt"
|
||||
],
|
||||
"time": "2018-08-03T11:23:50+00:00"
|
||||
"time": "2019-05-24T18:30:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/event",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/event.git",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd"
|
||||
"reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119",
|
||||
"reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -445,7 +442,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"henrikbjorn/phpspec-code-coverage": "~1.0.1",
|
||||
"phpspec/phpspec": "~2.0.0"
|
||||
"phpspec/phpspec": "^2.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -474,7 +471,7 @@
|
||||
"event",
|
||||
"listener"
|
||||
],
|
||||
"time": "2015-05-21T12:24:47+00:00"
|
||||
"time": "2018-11-26T11:52:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
@ -523,16 +520,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c"
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -571,20 +568,20 @@
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2018-07-30T21:54:04+00:00"
|
||||
"time": "2019-04-30T12:38:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "zendframework/zend-diactoros",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zendframework/zend-diactoros.git",
|
||||
"reference": "0bae78192e634774b5584f0210c1232da82cb1ff"
|
||||
"reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/0bae78192e634774b5584f0210c1232da82cb1ff",
|
||||
"reference": "0bae78192e634774b5584f0210c1232da82cb1ff",
|
||||
"url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/279723778c40164bcf984a2df12ff2c6ec5e61c1",
|
||||
"reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -607,8 +604,8 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev",
|
||||
"dev-develop": "2.1.x-dev",
|
||||
"dev-master": "2.1.x-dev",
|
||||
"dev-develop": "2.2.x-dev",
|
||||
"dev-release-1.8": "1.8.x-dev"
|
||||
}
|
||||
},
|
||||
@ -637,7 +634,7 @@
|
||||
"psr",
|
||||
"psr-7"
|
||||
],
|
||||
"time": "2018-09-27T19:49:04+00:00"
|
||||
"time": "2019-07-10T16:13:25+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -14,16 +14,33 @@ use OAuth2ServerExamples\Entities\ClientEntity;
|
||||
|
||||
class ClientRepository implements ClientRepositoryInterface
|
||||
{
|
||||
const CLIENT_NAME = 'My Awesome App';
|
||||
const REDIRECT_URI = 'http://foo/bar';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true)
|
||||
public function getClientEntity($clientIdentifier)
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
|
||||
$client->setIdentifier($clientIdentifier);
|
||||
$client->setName(self::CLIENT_NAME);
|
||||
$client->setRedirectUri(self::REDIRECT_URI);
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateClient($clientIdentifier, $clientSecret, $grantType)
|
||||
{
|
||||
$clients = [
|
||||
'myawesomeapp' => [
|
||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||
'name' => 'My Awesome App',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'name' => self::CLIENT_NAME,
|
||||
'redirect_uri' => self::REDIRECT_URI,
|
||||
'is_confidential' => true,
|
||||
],
|
||||
];
|
||||
@ -34,18 +51,10 @@ class ClientRepository implements ClientRepositoryInterface
|
||||
}
|
||||
|
||||
if (
|
||||
$mustValidateSecret === true
|
||||
&& $clients[$clientIdentifier]['is_confidential'] === true
|
||||
$clients[$clientIdentifier]['is_confidential'] === true
|
||||
&& password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$client = new ClientEntity();
|
||||
$client->setIdentifier($clientIdentifier);
|
||||
$client->setName($clients[$clientIdentifier]['name']);
|
||||
$client->setRedirectUri($clients[$clientIdentifier]['redirect_uri']);
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
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
|
||||
services:
|
||||
-
|
||||
class: LeagueTests\PHPStan\AbstractGrantExtension
|
||||
|
@ -125,7 +125,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
||||
*/
|
||||
public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL = null)
|
||||
{
|
||||
if ($accessTokenTTL instanceof DateInterval === false) {
|
||||
if ($accessTokenTTL === null) {
|
||||
$accessTokenTTL = new DateInterval('PT1H');
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ class BearerTokenValidator implements AuthorizationValidatorInterface
|
||||
}
|
||||
|
||||
$header = $request->getHeader('authorization');
|
||||
$jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0]));
|
||||
$jwt = trim((string) preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0]));
|
||||
|
||||
try {
|
||||
// Attempt to parse and validate the JWT
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukáš Unger <lookymsc@gmail.com>
|
||||
* @copyright Copyright (c) Lukáš Unger
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\CodeChallengeVerifiers;
|
||||
|
||||
interface CodeChallengeVerifierInterface
|
||||
{
|
||||
/**
|
||||
* Return code challenge method.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod();
|
||||
|
||||
/**
|
||||
* Verify the code challenge.
|
||||
*
|
||||
* @param string $codeVerifier
|
||||
* @param string $codeChallenge
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCodeChallenge($codeVerifier, $codeChallenge);
|
||||
}
|
36
src/CodeChallengeVerifiers/PlainVerifier.php
Normal file
36
src/CodeChallengeVerifiers/PlainVerifier.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukáš Unger <lookymsc@gmail.com>
|
||||
* @copyright Copyright (c) Lukáš Unger
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\CodeChallengeVerifiers;
|
||||
|
||||
class PlainVerifier implements CodeChallengeVerifierInterface
|
||||
{
|
||||
/**
|
||||
* Return code challenge method.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
return 'plain';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the code challenge.
|
||||
*
|
||||
* @param string $codeVerifier
|
||||
* @param string $codeChallenge
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCodeChallenge($codeVerifier, $codeChallenge)
|
||||
{
|
||||
return hash_equals($codeVerifier, $codeChallenge);
|
||||
}
|
||||
}
|
39
src/CodeChallengeVerifiers/S256Verifier.php
Normal file
39
src/CodeChallengeVerifiers/S256Verifier.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukáš Unger <lookymsc@gmail.com>
|
||||
* @copyright Copyright (c) Lukáš Unger
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\CodeChallengeVerifiers;
|
||||
|
||||
class S256Verifier implements CodeChallengeVerifierInterface
|
||||
{
|
||||
/**
|
||||
* Return code challenge method.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
return 'S256';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the code challenge.
|
||||
*
|
||||
* @param string $codeVerifier
|
||||
* @param string $codeChallenge
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCodeChallenge($codeVerifier, $codeChallenge)
|
||||
{
|
||||
return hash_equals(
|
||||
strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_'),
|
||||
$codeChallenge
|
||||
);
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ use LogicException;
|
||||
trait CryptTrait
|
||||
{
|
||||
/**
|
||||
* @var string|Key
|
||||
* @var string|Key|null
|
||||
*/
|
||||
protected $encryptionKey;
|
||||
|
||||
@ -39,9 +39,13 @@ trait CryptTrait
|
||||
return Crypto::encrypt($unencryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
|
||||
if (is_string($this->encryptionKey)) {
|
||||
return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
throw new LogicException('Encryption key not set when attempting to encrypt');
|
||||
} catch (Exception $e) {
|
||||
throw new LogicException($e->getMessage(), null, $e);
|
||||
throw new LogicException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,9 +65,13 @@ trait CryptTrait
|
||||
return Crypto::decrypt($encryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
|
||||
if (is_string($this->encryptionKey)) {
|
||||
return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
throw new LogicException('Encryption key not set when attempting to decrypt');
|
||||
} catch (Exception $e) {
|
||||
throw new LogicException($e->getMessage(), null, $e);
|
||||
throw new LogicException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,17 +9,17 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use Lcobucci\JWT\Token;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
|
||||
interface AccessTokenEntityInterface extends TokenInterface
|
||||
{
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
* @param CryptKey $privateKey
|
||||
*
|
||||
* @return Token
|
||||
* Set a private key used to encrypt the access token.
|
||||
*/
|
||||
public function convertToJWT(CryptKey $privateKey);
|
||||
public function setPrivateKey(CryptKey $privateKey);
|
||||
|
||||
/**
|
||||
* Generate a string representation of the access token.
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
||||
|
@ -33,4 +33,11 @@ interface ClientEntityInterface
|
||||
* @return string|string[]
|
||||
*/
|
||||
public function getRedirectUri();
|
||||
|
||||
/**
|
||||
* Returns true if the client is confidential.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConfidential();
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface RefreshTokenEntityInterface
|
||||
{
|
||||
@ -30,16 +30,16 @@ interface RefreshTokenEntityInterface
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
* @param DateTimeImmutable $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime);
|
||||
public function setExpiryDateTime(DateTimeImmutable $dateTime);
|
||||
|
||||
/**
|
||||
* Set the access token that the refresh token was associated with.
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface TokenInterface
|
||||
{
|
||||
@ -30,16 +30,16 @@ interface TokenInterface
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
* @param DateTimeImmutable $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime);
|
||||
public function setExpiryDateTime(DateTimeImmutable $dateTime);
|
||||
|
||||
/**
|
||||
* Set the identifier of the user associated with the token.
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Lcobucci\JWT\Builder;
|
||||
use Lcobucci\JWT\Signer\Key;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
@ -20,6 +20,19 @@ use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
trait AccessTokenTrait
|
||||
{
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
private $privateKey;
|
||||
|
||||
/**
|
||||
* Set the private key used to encrypt this access token.
|
||||
*/
|
||||
public function setPrivateKey(CryptKey $privateKey)
|
||||
{
|
||||
$this->privateKey = $privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
@ -27,27 +40,35 @@ trait AccessTokenTrait
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function convertToJWT(CryptKey $privateKey)
|
||||
private function convertToJWT(CryptKey $privateKey)
|
||||
{
|
||||
return (new Builder())
|
||||
->setAudience($this->getClient()->getIdentifier())
|
||||
->setId($this->getIdentifier(), true)
|
||||
->setId($this->getIdentifier())
|
||||
->setIssuedAt(time())
|
||||
->setNotBefore(time())
|
||||
->setExpiration($this->getExpiryDateTime()->getTimestamp())
|
||||
->setSubject($this->getUserIdentifier())
|
||||
->setSubject((string) $this->getUserIdentifier())
|
||||
->set('scopes', $this->getScopes())
|
||||
->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
|
||||
->getToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a string representation from the access token
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->convertToJWT($this->privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
abstract public function getClient();
|
||||
|
||||
/**
|
||||
* @return DateTime
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
abstract public function getExpiryDateTime();
|
||||
|
||||
|
@ -21,6 +21,11 @@ trait ClientTrait
|
||||
*/
|
||||
protected $redirectUri;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isConfidential = false;
|
||||
|
||||
/**
|
||||
* Get the client's name.
|
||||
*
|
||||
@ -43,4 +48,14 @@ trait ClientTrait
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the client is confidential.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConfidential()
|
||||
{
|
||||
return $this->isConfidential;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
|
||||
trait RefreshTokenTrait
|
||||
@ -20,7 +20,7 @@ trait RefreshTokenTrait
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @var DateTime
|
||||
* @var DateTimeImmutable
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
@ -43,7 +43,7 @@ trait RefreshTokenTrait
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
@ -53,9 +53,9 @@ trait RefreshTokenTrait
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
* @param DateTimeImmutable $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime)
|
||||
public function setExpiryDateTime(DateTimeImmutable $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
@ -21,7 +21,7 @@ trait TokenEntityTrait
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* @var DateTime
|
||||
* @var DateTimeImmutable
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
@ -58,7 +58,7 @@ trait TokenEntityTrait
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
@ -68,9 +68,9 @@ trait TokenEntityTrait
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
* @param DateTimeImmutable $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime)
|
||||
public function setExpiryDateTime(DateTimeImmutable $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ namespace League\OAuth2\Server\Exception;
|
||||
|
||||
use Exception;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Throwable;
|
||||
|
||||
class OAuthServerException extends Exception
|
||||
@ -40,6 +41,11 @@ class OAuthServerException extends Exception
|
||||
*/
|
||||
private $payload;
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
*/
|
||||
private $serverRequest;
|
||||
|
||||
/**
|
||||
* Throw a new exception.
|
||||
*
|
||||
@ -95,6 +101,16 @@ class OAuthServerException extends Exception
|
||||
$this->payload = $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server request that is responsible for generating the exception
|
||||
*
|
||||
* @param ServerRequestInterface $serverRequest
|
||||
*/
|
||||
public function setServerRequest(ServerRequestInterface $serverRequest)
|
||||
{
|
||||
$this->serverRequest = $serverRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported grant type error.
|
||||
*
|
||||
@ -129,13 +145,17 @@ class OAuthServerException extends Exception
|
||||
/**
|
||||
* Invalid client error.
|
||||
*
|
||||
* @param ServerRequestInterface $serverRequest
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidClient()
|
||||
public static function invalidClient(ServerRequestInterface $serverRequest)
|
||||
{
|
||||
$errorMessage = 'Client authentication failed';
|
||||
$exception = new static('Client authentication failed', 4, 'invalid_client', 401);
|
||||
|
||||
return new static($errorMessage, 4, 'invalid_client', 401);
|
||||
$exception->setServerRequest($serverRequest);
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,7 +308,9 @@ class OAuthServerException extends Exception
|
||||
$response = $response->withHeader($header, $content);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode($payload, $jsonOptions));
|
||||
$responseBody = json_encode($payload, $jsonOptions) ?: 'JSON encoding of payload failed';
|
||||
|
||||
$response->getBody()->write($responseBody);
|
||||
|
||||
return $response->withStatus($this->getHttpStatusCode());
|
||||
}
|
||||
@ -313,8 +335,8 @@ class OAuthServerException extends Exception
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->errorType === 'invalid_client' && array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false) {
|
||||
$authScheme = strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0 ? 'Bearer' : 'Basic';
|
||||
if ($this->errorType === 'invalid_client' && $this->serverRequest->hasHeader('Authorization') === true) {
|
||||
$authScheme = strpos($this->serverRequest->getHeader('Authorization')[0], 'Bearer') === 0 ? 'Bearer' : 'Basic';
|
||||
|
||||
$headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Error;
|
||||
use Exception;
|
||||
use League\Event\EmitterAwareTrait;
|
||||
@ -177,28 +177,17 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
|
||||
list($clientId, $clientSecret) = $this->getClientCredentials($request);
|
||||
|
||||
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
|
||||
if ($clientId === null) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
// If the client is confidential require the client secret
|
||||
$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
$clientSecret,
|
||||
true
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
if ($this->clientRepository->validateClient($clientId, $clientSecret, $this->getIdentifier()) === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
}
|
||||
|
||||
$client = $this->getClientEntityOrFail($clientId, $request);
|
||||
|
||||
// If a redirect URI is provided ensure it matches what is pre-registered
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
|
||||
if ($redirectUri !== null) {
|
||||
@ -208,6 +197,56 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around ClientRepository::getClientEntity() that ensures we emit
|
||||
* an event and throw an exception if the repo doesn't return a client
|
||||
* entity.
|
||||
*
|
||||
* This is a bit of defensive coding because the interface contract
|
||||
* doesn't actually enforce non-null returns/exception-on-no-client so
|
||||
* getClientEntity might return null. By contrast, this method will
|
||||
* always either return a ClientEntityInterface or throw.
|
||||
*
|
||||
* @param string $clientId
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
protected function getClientEntityOrFail($clientId, ServerRequestInterface $request)
|
||||
{
|
||||
$client = $this->clientRepository->getClientEntity($clientId);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client credentials from the request from the request body or
|
||||
* the Http Basic Authorization header
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getClientCredentials(ServerRequestInterface $request)
|
||||
{
|
||||
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
|
||||
|
||||
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
|
||||
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
|
||||
|
||||
return [$clientId, $clientSecret];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate redirectUri from the request.
|
||||
* If a redirect URI is provided ensure it matches what is pre-registered
|
||||
@ -227,12 +266,12 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
} elseif (\is_array($client->getRedirectUri())
|
||||
&& \in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,13 +433,8 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
$accessToken->setExpiryDateTime((new DateTime())->add($accessTokenTTL));
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add($accessTokenTTL));
|
||||
$accessToken->setPrivateKey($this->privateKey);
|
||||
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
@ -440,7 +474,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$authCode = $this->authCodeRepository->getNewAuthCode();
|
||||
$authCode->setExpiryDateTime((new DateTime())->add($authCodeTTL));
|
||||
$authCode->setExpiryDateTime((new DateTimeImmutable())->add($authCodeTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
|
||||
@ -482,7 +516,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
$refreshToken->setExpiryDateTime((new DateTime())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
@ -10,8 +10,11 @@
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use League\OAuth2\Server\CodeChallengeVerifiers\CodeChallengeVerifierInterface;
|
||||
use League\OAuth2\Server\CodeChallengeVerifiers\PlainVerifier;
|
||||
use League\OAuth2\Server\CodeChallengeVerifiers\S256Verifier;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
@ -35,7 +38,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $enableCodeExchangeProof = false;
|
||||
private $requireCodeChallengeForPublicClients = true;
|
||||
|
||||
/**
|
||||
* @var CodeChallengeVerifierInterface[]
|
||||
*/
|
||||
private $codeChallengeVerifiers = [];
|
||||
|
||||
/**
|
||||
* @param AuthCodeRepositoryInterface $authCodeRepository
|
||||
@ -53,11 +61,22 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
$this->authCodeTTL = $authCodeTTL;
|
||||
$this->refreshTokenTTL = new DateInterval('P1M');
|
||||
|
||||
if (in_array('sha256', hash_algos(), true)) {
|
||||
$s256Verifier = new S256Verifier();
|
||||
$this->codeChallengeVerifiers[$s256Verifier->getMethod()] = $s256Verifier;
|
||||
}
|
||||
|
||||
$plainVerifier = new PlainVerifier();
|
||||
$this->codeChallengeVerifiers[$plainVerifier->getMethod()] = $plainVerifier;
|
||||
}
|
||||
|
||||
public function enableCodeExchangeProof()
|
||||
/**
|
||||
* Disable the requirement for a code challenge for public clients.
|
||||
*/
|
||||
public function disableRequireCodeChallengeForPublicClients()
|
||||
{
|
||||
$this->enableCodeExchangeProof = true;
|
||||
$this->requireCodeChallengeForPublicClients = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,8 +95,15 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
ResponseTypeInterface $responseType,
|
||||
DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
list($clientId) = $this->getClientCredentials($request);
|
||||
|
||||
$client = $this->getClientEntityOrFail($clientId, $request);
|
||||
|
||||
// Only validate the client if it is confidential
|
||||
if ($client->isConfidential()) {
|
||||
$this->validateClient($request);
|
||||
}
|
||||
|
||||
$encryptedAuthCode = $this->getRequestParameter('code', $request, null);
|
||||
|
||||
if ($encryptedAuthCode === null) {
|
||||
@ -100,7 +126,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
}
|
||||
|
||||
// Validate code challenge
|
||||
if ($this->enableCodeExchangeProof === true) {
|
||||
if (!empty($authCodePayload->code_challenge)) {
|
||||
$codeVerifier = $this->getRequestParameter('code_verifier', $request, null);
|
||||
|
||||
if ($codeVerifier === null) {
|
||||
@ -116,32 +142,21 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
);
|
||||
}
|
||||
|
||||
switch ($authCodePayload->code_challenge_method) {
|
||||
case 'plain':
|
||||
if (hash_equals($codeVerifier, $authCodePayload->code_challenge) === false) {
|
||||
throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
|
||||
}
|
||||
if (property_exists($authCodePayload, 'code_challenge_method')) {
|
||||
if (isset($this->codeChallengeVerifiers[$authCodePayload->code_challenge_method])) {
|
||||
$codeChallengeVerifier = $this->codeChallengeVerifiers[$authCodePayload->code_challenge_method];
|
||||
|
||||
break;
|
||||
case 'S256':
|
||||
if (
|
||||
hash_equals(
|
||||
strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_'),
|
||||
$authCodePayload->code_challenge
|
||||
) === false
|
||||
) {
|
||||
if ($codeChallengeVerifier->verifyCodeChallenge($codeVerifier, $authCodePayload->code_challenge) === false) {
|
||||
throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
throw OAuthServerException::serverError(
|
||||
sprintf(
|
||||
'Unsupported code challenge method `%s`',
|
||||
$authCodePayload->code_challenge_method
|
||||
)
|
||||
);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,17 +251,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
$client = $this->getClientEntityOrFail($clientId, $request);
|
||||
|
||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
||||
|
||||
@ -255,7 +260,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
} elseif (empty($client->getRedirectUri()) ||
|
||||
(\is_array($client->getRedirectUri()) && \count($client->getRedirectUri()) !== 1)) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
} else {
|
||||
$redirectUri = \is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
@ -280,18 +285,20 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
|
||||
$authorizationRequest->setScopes($scopes);
|
||||
|
||||
if ($this->enableCodeExchangeProof === true) {
|
||||
$codeChallenge = $this->getQueryStringParameter('code_challenge', $request);
|
||||
if ($codeChallenge === null) {
|
||||
throw OAuthServerException::invalidRequest('code_challenge');
|
||||
}
|
||||
$codeChallenge = $this->getQueryStringParameter('code_challenge', $request);
|
||||
|
||||
if ($codeChallenge !== null) {
|
||||
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
||||
|
||||
if (\in_array($codeChallengeMethod, ['plain', 'S256'], true) === false) {
|
||||
if (array_key_exists($codeChallengeMethod, $this->codeChallengeVerifiers) === false) {
|
||||
throw OAuthServerException::invalidRequest(
|
||||
'code_challenge_method',
|
||||
'Code challenge method must be `plain` or `S256`'
|
||||
'Code challenge method must be one of ' . implode(', ', array_map(
|
||||
function ($method) {
|
||||
return '`' . $method . '`';
|
||||
},
|
||||
array_keys($this->codeChallengeVerifiers)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@ -306,6 +313,8 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
|
||||
$authorizationRequest->setCodeChallenge($codeChallenge);
|
||||
$authorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
|
||||
} elseif ($this->requireCodeChallengeForPublicClients && !$client->isConfidential()) {
|
||||
throw OAuthServerException::invalidRequest('code_challenge', 'Code challenge must be provided for public clients');
|
||||
}
|
||||
|
||||
return $authorizationRequest;
|
||||
@ -339,21 +348,23 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
'auth_code_id' => $authCode->getIdentifier(),
|
||||
'scopes' => $authCode->getScopes(),
|
||||
'user_id' => $authCode->getUserIdentifier(),
|
||||
'expire_time' => (new DateTime())->add($this->authCodeTTL)->format('U'),
|
||||
'expire_time' => (new DateTimeImmutable())->add($this->authCodeTTL)->getTimestamp(),
|
||||
'code_challenge' => $authorizationRequest->getCodeChallenge(),
|
||||
'code_challenge_method' => $authorizationRequest->getCodeChallengeMethod(),
|
||||
];
|
||||
|
||||
$jsonPayload = json_encode($payload);
|
||||
|
||||
if ($jsonPayload === false) {
|
||||
throw new LogicException('An error was encountered when JSON encoding the authorization request response');
|
||||
}
|
||||
|
||||
$response = new RedirectResponse();
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'code' => $this->encrypt(
|
||||
json_encode(
|
||||
$payload
|
||||
)
|
||||
),
|
||||
'code' => $this->encrypt($jsonPayload),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
|
@ -10,8 +10,6 @@
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
@ -126,17 +124,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
$client = $this->getClientEntityOrFail($clientId, $request);
|
||||
|
||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
||||
|
||||
@ -145,7 +133,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
||||
|| empty($client->getRedirectUri())) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
throw OAuthServerException::invalidClient($request);
|
||||
} else {
|
||||
$redirectUri = is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
@ -210,9 +198,9 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
||||
'access_token' => (string) $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new DateTime())->getTimestamp(),
|
||||
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - \time(),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
],
|
||||
$this->queryDelimiter
|
||||
|
@ -83,11 +83,13 @@ class PasswordGrant extends AbstractGrant
|
||||
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
|
||||
{
|
||||
$username = $this->getRequestParameter('username', $request);
|
||||
|
||||
if (is_null($username)) {
|
||||
throw OAuthServerException::invalidRequest('username');
|
||||
}
|
||||
|
||||
$password = $this->getRequestParameter('password', $request);
|
||||
|
||||
if (is_null($password)) {
|
||||
throw OAuthServerException::invalidRequest('password');
|
||||
}
|
||||
@ -98,10 +100,11 @@ class PasswordGrant extends AbstractGrant
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
|
||||
if ($user instanceof UserEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
|
||||
|
||||
throw OAuthServerException::invalidCredentials();
|
||||
throw OAuthServerException::invalidGrant();
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
@ -19,13 +19,20 @@ interface ClientRepositoryInterface extends RepositoryInterface
|
||||
/**
|
||||
* Get a client.
|
||||
*
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
* @param null|string $grantType The grant type used (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
|
||||
* is confidential
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
* @return ClientEntityInterface|null
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true);
|
||||
public function getClientEntity($clientIdentifier);
|
||||
|
||||
/**
|
||||
* Validate a client's secret.
|
||||
*
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
* @param null|string $clientSecret The client's secret (if sent)
|
||||
* @param null|string $grantType The type of grant the client is using (if sent)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateClient($clientIdentifier, $clientSecret, $grantType);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ interface ScopeRepositoryInterface extends RepositoryInterface
|
||||
*
|
||||
* @param string $identifier The scope identifier
|
||||
*
|
||||
* @return ScopeEntityInterface
|
||||
* @return ScopeEntityInterface|null
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($identifier);
|
||||
|
||||
|
@ -22,7 +22,7 @@ interface UserRepositoryInterface extends RepositoryInterface
|
||||
* @param string $grantType The grant type used
|
||||
* @param ClientEntityInterface $clientEntity
|
||||
*
|
||||
* @return UserEntityInterface
|
||||
* @return UserEntityInterface|null
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
|
@ -111,7 +111,7 @@ class AuthorizationRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UserEntityInterface
|
||||
* @return UserEntityInterface|null
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
|
@ -11,9 +11,9 @@
|
||||
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use DateTime;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use LogicException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class BearerTokenResponse extends AbstractResponseType
|
||||
@ -25,32 +25,34 @@ class BearerTokenResponse extends AbstractResponseType
|
||||
{
|
||||
$expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp();
|
||||
|
||||
$jwtAccessToken = $this->accessToken->convertToJWT($this->privateKey);
|
||||
|
||||
$responseParams = [
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => $expireDateTime - (new DateTime())->getTimestamp(),
|
||||
'access_token' => (string) $jwtAccessToken,
|
||||
'expires_in' => $expireDateTime - \time(),
|
||||
'access_token' => (string) $this->accessToken,
|
||||
];
|
||||
|
||||
if ($this->refreshToken instanceof RefreshTokenEntityInterface) {
|
||||
$refreshToken = $this->encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $this->accessToken->getClient()->getIdentifier(),
|
||||
'refresh_token_id' => $this->refreshToken->getIdentifier(),
|
||||
'access_token_id' => $this->accessToken->getIdentifier(),
|
||||
'scopes' => $this->accessToken->getScopes(),
|
||||
'user_id' => $this->accessToken->getUserIdentifier(),
|
||||
'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(),
|
||||
]
|
||||
)
|
||||
);
|
||||
$refreshTokenPayload = json_encode([
|
||||
'client_id' => $this->accessToken->getClient()->getIdentifier(),
|
||||
'refresh_token_id' => $this->refreshToken->getIdentifier(),
|
||||
'access_token_id' => $this->accessToken->getIdentifier(),
|
||||
'scopes' => $this->accessToken->getScopes(),
|
||||
'user_id' => $this->accessToken->getUserIdentifier(),
|
||||
'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(),
|
||||
]);
|
||||
|
||||
$responseParams['refresh_token'] = $refreshToken;
|
||||
if ($refreshTokenPayload === false) {
|
||||
throw new LogicException('Error encountered JSON encoding the refresh token payload');
|
||||
}
|
||||
|
||||
$responseParams['refresh_token'] = $this->encrypt($refreshTokenPayload);
|
||||
}
|
||||
|
||||
$responseParams = array_merge($this->getExtraParams($this->accessToken), $responseParams);
|
||||
$responseParams = json_encode(array_merge($this->getExtraParams($this->accessToken), $responseParams));
|
||||
|
||||
if ($responseParams === false) {
|
||||
throw new LogicException('Error encountered JSON encoding response parameters');
|
||||
}
|
||||
|
||||
$response = $response
|
||||
->withStatus(200)
|
||||
@ -58,7 +60,7 @@ class BearerTokenResponse extends AbstractResponseType
|
||||
->withHeader('cache-control', 'no-store')
|
||||
->withHeader('content-type', 'application/json; charset=UTF-8');
|
||||
|
||||
$response->getBody()->write(json_encode($responseParams));
|
||||
$response->getBody()->write($responseParams);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace LeagueTests;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
@ -30,7 +31,7 @@ class AuthorizationServerTest extends TestCase
|
||||
{
|
||||
const DEFAULT_SCOPE = 'basic';
|
||||
|
||||
public function setUp()
|
||||
public function setUp(): void
|
||||
{
|
||||
// Make sure the keys have the correct permissions.
|
||||
chmod(__DIR__ . '/Stubs/private.key', 0600);
|
||||
@ -49,7 +50,7 @@ class AuthorizationServerTest extends TestCase
|
||||
new StubResponseType()
|
||||
);
|
||||
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M'));
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new DateInterval('PT1M'));
|
||||
|
||||
try {
|
||||
$server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response);
|
||||
@ -82,7 +83,7 @@ class AuthorizationServerTest extends TestCase
|
||||
);
|
||||
|
||||
$server->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M'));
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new DateInterval('PT1M'));
|
||||
|
||||
$_POST['grant_type'] = 'client_credentials';
|
||||
$_POST['client_id'] = 'foo';
|
||||
@ -116,35 +117,31 @@ class AuthorizationServerTest extends TestCase
|
||||
$privateKey = 'file://' . __DIR__ . '/Stubs/private.key';
|
||||
$encryptionKey = 'file://' . __DIR__ . '/Stubs/public.key';
|
||||
|
||||
$server = new class($clientRepository, $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(), $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(), $privateKey, $encryptionKey) extends AuthorizationServer {
|
||||
protected function getResponseType()
|
||||
{
|
||||
$this->responseType = new class extends BearerTokenResponse {
|
||||
/* @return null|CryptKey */
|
||||
public function getPrivateKey()
|
||||
{
|
||||
return $this->privateKey;
|
||||
}
|
||||
|
||||
public function getEncryptionKey()
|
||||
{
|
||||
return $this->encryptionKey;
|
||||
}
|
||||
};
|
||||
|
||||
return parent::getResponseType();
|
||||
}
|
||||
};
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
||||
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
||||
'file://' . __DIR__ . '/Stubs/private.key',
|
||||
'file://' . __DIR__ . '/Stubs/public.key'
|
||||
);
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($server);
|
||||
$method = $abstractGrantReflection->getMethod('getResponseType');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$responseType = $method->invoke($server);
|
||||
|
||||
$this->assertInstanceOf(BearerTokenResponse::class, $responseType);
|
||||
$responseTypeReflection = new \ReflectionClass($responseType);
|
||||
|
||||
$privateKeyProperty = $responseTypeReflection->getProperty('privateKey');
|
||||
$privateKeyProperty->setAccessible(true);
|
||||
|
||||
$encryptionKeyProperty = $responseTypeReflection->getProperty('encryptionKey');
|
||||
$encryptionKeyProperty->setAccessible(true);
|
||||
|
||||
// generated instances should have keys setup
|
||||
$this->assertSame($privateKey, $responseType->getPrivateKey()->getKeyPath());
|
||||
$this->assertSame($encryptionKey, $responseType->getEncryptionKey());
|
||||
$this->assertSame($privateKey, $privateKeyProperty->getValue($responseType)->getKeyPath());
|
||||
$this->assertSame($encryptionKey, $encryptionKeyProperty->getValue($responseType));
|
||||
}
|
||||
|
||||
public function testMultipleRequestsGetDifferentResponseTypeInstances()
|
||||
@ -217,7 +214,7 @@ class AuthorizationServerTest extends TestCase
|
||||
$grant = new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||
new \DateInterval('PT10M')
|
||||
new DateInterval('PT10M')
|
||||
);
|
||||
|
||||
$server->enableGrantType($grant);
|
||||
@ -238,6 +235,7 @@ class AuthorizationServerTest extends TestCase
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setRedirectUri('http://foo/bar');
|
||||
$client->setConfidential();
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
@ -248,7 +246,7 @@ class AuthorizationServerTest extends TestCase
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||
new \DateInterval('PT10M')
|
||||
new DateInterval('PT10M')
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
@ -289,7 +287,7 @@ class AuthorizationServerTest extends TestCase
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||
new \DateInterval('PT10M')
|
||||
new DateInterval('PT10M')
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
@ -324,10 +322,6 @@ class AuthorizationServerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 2
|
||||
*/
|
||||
public function testValidateAuthorizationRequestUnregistered()
|
||||
{
|
||||
$server = new AuthorizationServer(
|
||||
@ -338,19 +332,13 @@ class AuthorizationServerTest extends TestCase
|
||||
'file://' . __DIR__ . '/Stubs/public.key'
|
||||
);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(2);
|
||||
|
||||
$server->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
@ -11,10 +11,6 @@ use Zend\Diactoros\ServerRequest;
|
||||
|
||||
class BearerTokenValidatorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 9
|
||||
*/
|
||||
public function testThrowExceptionWhenAccessTokenIsNotSigned()
|
||||
{
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
@ -32,8 +28,10 @@ class BearerTokenValidatorTest extends TestCase
|
||||
->set('scopes', 'scope1 scope2 scope3 scope4')
|
||||
->getToken();
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $unsignedJwt));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $unsignedJwt));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(9);
|
||||
|
||||
$bearerTokenValidator->validateAuthorization($request);
|
||||
}
|
||||
|
24
tests/CodeChallengeVerifiers/PlainVerifierTest.php
Normal file
24
tests/CodeChallengeVerifiers/PlainVerifierTest.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests\CodeChallengeVerifiers;
|
||||
|
||||
use League\OAuth2\Server\CodeChallengeVerifiers\PlainVerifier;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PlainVerifierTest extends TestCase
|
||||
{
|
||||
public function testGetMethod()
|
||||
{
|
||||
$verifier = new PlainVerifier();
|
||||
|
||||
$this->assertEquals('plain', $verifier->getMethod());
|
||||
}
|
||||
|
||||
public function testVerifyCodeChallenge()
|
||||
{
|
||||
$verifier = new PlainVerifier();
|
||||
|
||||
$this->assertTrue($verifier->verifyCodeChallenge('foo', 'foo'));
|
||||
$this->assertFalse($verifier->verifyCodeChallenge('foo', 'bar'));
|
||||
}
|
||||
}
|
37
tests/CodeChallengeVerifiers/S256VerifierTest.php
Normal file
37
tests/CodeChallengeVerifiers/S256VerifierTest.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests\CodeChallengeVerifiers;
|
||||
|
||||
use League\OAuth2\Server\CodeChallengeVerifiers\S256Verifier;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class S256VerifierTest extends TestCase
|
||||
{
|
||||
public function testGetMethod()
|
||||
{
|
||||
$verifier = new S256Verifier();
|
||||
|
||||
$this->assertEquals('S256', $verifier->getMethod());
|
||||
}
|
||||
|
||||
public function testVerifyCodeChallengeSucceeds()
|
||||
{
|
||||
$codeChallenge = $this->createCodeChallenge('foo');
|
||||
$verifier = new S256Verifier();
|
||||
|
||||
$this->assertTrue($verifier->verifyCodeChallenge('foo', $codeChallenge));
|
||||
}
|
||||
|
||||
public function testVerifyCodeChallengeFails()
|
||||
{
|
||||
$codeChallenge = $this->createCodeChallenge('bar');
|
||||
$verifier = new S256Verifier();
|
||||
|
||||
$this->assertFalse($verifier->verifyCodeChallenge('foo', $codeChallenge));
|
||||
}
|
||||
|
||||
private function createCodeChallenge($codeVerifier)
|
||||
{
|
||||
return strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_');
|
||||
}
|
||||
}
|
@ -4,10 +4,68 @@ namespace LeagueTests\Exception;
|
||||
|
||||
use Exception;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\AbstractGrant;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
|
||||
class OAuthServerExceptionTest extends TestCase
|
||||
{
|
||||
public function testInvalidClientExceptionSetsAuthenticateHeader()
|
||||
{
|
||||
$serverRequest = (new ServerRequest())
|
||||
->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
])
|
||||
->withAddedHeader('Authorization', 'Basic fakeauthdetails');
|
||||
|
||||
try {
|
||||
$this->issueInvalidClientException($serverRequest);
|
||||
} catch (OAuthServerException $e) {
|
||||
$response = $e->generateHttpResponse(new Response());
|
||||
|
||||
$this->assertTrue($response->hasHeader('WWW-Authenticate'));
|
||||
}
|
||||
}
|
||||
|
||||
public function testInvalidClientExceptionOmitsAuthenticateHeader()
|
||||
{
|
||||
$serverRequest = (new ServerRequest())
|
||||
->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
try {
|
||||
$this->issueInvalidClientException($serverRequest);
|
||||
} catch (OAuthServerException $e) {
|
||||
$response = $e->generateHttpResponse(new Response());
|
||||
|
||||
$this->assertFalse($response->hasHeader('WWW-Authenticate'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an invalid client exception
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*/
|
||||
private function issueInvalidClientException($serverRequest)
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('validateClient')->willReturn(false);
|
||||
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest);
|
||||
}
|
||||
|
||||
public function testHasRedirect()
|
||||
{
|
||||
$exceptionWithRedirect = OAuthServerException::accessDenied('some hint', 'https://example.com/error');
|
||||
@ -27,7 +85,9 @@ class OAuthServerExceptionTest extends TestCase
|
||||
$previous = new Exception('This is the previous');
|
||||
$exceptionWithPrevious = OAuthServerException::accessDenied(null, null, $previous);
|
||||
|
||||
$this->assertSame('This is the previous', $exceptionWithPrevious->getPrevious()->getMessage());
|
||||
$previousMessage = $exceptionWithPrevious->getPrevious() !== null ? $exceptionWithPrevious->getPrevious()->getMessage() : null;
|
||||
|
||||
$this->assertSame('This is the previous', $previousMessage);
|
||||
}
|
||||
|
||||
public function testDoesNotHavePrevious()
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use League\Event\Emitter;
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
@ -23,21 +24,13 @@ use Zend\Diactoros\ServerRequest;
|
||||
|
||||
class AbstractGrantTest extends TestCase
|
||||
{
|
||||
public function testGetSet()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->setEmitter(new Emitter());
|
||||
}
|
||||
|
||||
public function testHttpBasicWithPassword()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:Sesame'));
|
||||
$serverRequest = (new ServerRequest())->withHeader('Authorization', 'Basic ' . base64_encode('Open:Sesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
@ -50,8 +43,7 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:'));
|
||||
$serverRequest = (new ServerRequest())->withHeader('Authorization', 'Basic ' . base64_encode('Open:'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
@ -64,8 +56,7 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Foo ' . base64_encode('Open:Sesame'));
|
||||
$serverRequest = (new ServerRequest())->withHeader('Authorization', 'Foo ' . base64_encode('Open:Sesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
@ -78,8 +69,7 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ||');
|
||||
$serverRequest = (new ServerRequest())->withHeader('Authorization', 'Basic ||');
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
@ -92,8 +82,7 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('OpenSesame'));
|
||||
$serverRequest = (new ServerRequest())->withHeader('Authorization', 'Basic ' . base64_encode('OpenSesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
@ -113,16 +102,14 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$result = $validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
$result = $validateClientMethod->invoke($grantMock, $serverRequest);
|
||||
$this->assertEquals($client, $result);
|
||||
}
|
||||
|
||||
@ -139,14 +126,12 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]);
|
||||
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
@ -154,9 +139,6 @@ class AbstractGrantTest extends TestCase
|
||||
$this->assertEquals($client, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientMissingClientId()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -173,16 +155,15 @@ class AbstractGrantTest extends TestCase
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientMissingClientSecret()
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn(null);
|
||||
$clientRepositoryMock->method('validateClient')->willReturn(false);
|
||||
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
@ -190,24 +171,22 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientInvalidClientSecret()
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn(null);
|
||||
$clientRepositoryMock->method('validateClient')->willReturn(false);
|
||||
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
@ -215,8 +194,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'foo',
|
||||
]);
|
||||
@ -224,12 +202,11 @@ class AbstractGrantTest extends TestCase
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientInvalidRedirectUri()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -243,8 +220,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar/foo',
|
||||
]);
|
||||
@ -252,12 +228,11 @@ class AbstractGrantTest extends TestCase
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientInvalidRedirectUriArray()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -271,8 +246,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar/foo',
|
||||
]);
|
||||
@ -280,16 +254,15 @@ class AbstractGrantTest extends TestCase
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateClientBadClient()
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn(null);
|
||||
$clientRepositoryMock->method('validateClient')->willReturn(false);
|
||||
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
@ -297,8 +270,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]);
|
||||
@ -306,6 +278,8 @@ class AbstractGrantTest extends TestCase
|
||||
$validateClientMethod = $abstractGrantReflection->getMethod('validateClient');
|
||||
$validateClientMethod->setAccessible(true);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$validateClientMethod->invoke($grantMock, $serverRequest, true);
|
||||
}
|
||||
|
||||
@ -314,8 +288,7 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->method('getIdentifier')->willReturn('foobar');
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'grant_type' => 'foobar',
|
||||
]);
|
||||
|
||||
@ -332,7 +305,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->setRefreshTokenTTL(new \DateInterval('PT1M'));
|
||||
$grantMock->setRefreshTokenTTL(new DateInterval('PT1M'));
|
||||
$grantMock->setRefreshTokenRepository($refreshTokenRepoMock);
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
@ -374,6 +347,7 @@ class AbstractGrantTest extends TestCase
|
||||
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grantMock->setAccessTokenRepository($accessTokenRepoMock);
|
||||
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
@ -383,7 +357,7 @@ class AbstractGrantTest extends TestCase
|
||||
/** @var AccessTokenEntityInterface $accessToken */
|
||||
$accessToken = $issueAccessTokenMethod->invoke(
|
||||
$grantMock,
|
||||
new \DateInterval('PT1H'),
|
||||
new DateInterval('PT1H'),
|
||||
new ClientEntity(),
|
||||
123,
|
||||
[new ScopeEntity()]
|
||||
@ -408,7 +382,7 @@ class AbstractGrantTest extends TestCase
|
||||
AuthCodeEntityInterface::class,
|
||||
$issueAuthCodeMethod->invoke(
|
||||
$grantMock,
|
||||
new \DateInterval('PT1H'),
|
||||
new DateInterval('PT1H'),
|
||||
new ClientEntity(),
|
||||
123,
|
||||
'http://foo/bar',
|
||||
@ -426,8 +400,7 @@ class AbstractGrantTest extends TestCase
|
||||
$method = $abstractGrantReflection->getMethod('getCookieParameter');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withCookieParams([
|
||||
$serverRequest = (new ServerRequest())->withCookieParams([
|
||||
'foo' => 'bar',
|
||||
]);
|
||||
|
||||
@ -444,8 +417,7 @@ class AbstractGrantTest extends TestCase
|
||||
$method = $abstractGrantReflection->getMethod('getQueryStringParameter');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withQueryParams([
|
||||
$serverRequest = (new ServerRequest())->withQueryParams([
|
||||
'foo' => 'bar',
|
||||
]);
|
||||
|
||||
@ -466,9 +438,6 @@ class AbstractGrantTest extends TestCase
|
||||
$this->assertEquals([$scope], $grantMock->validateScopes('basic '));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testValidateScopesBadScope()
|
||||
{
|
||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||
@ -478,6 +447,8 @@ class AbstractGrantTest extends TestCase
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$grantMock->setScopeRepository($scopeRepositoryMock);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$grantMock->validateScopes('basic ');
|
||||
}
|
||||
|
||||
@ -489,7 +460,7 @@ class AbstractGrantTest extends TestCase
|
||||
$method = $abstractGrantReflection->getMethod('generateUniqueIdentifier');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$this->assertInternalType('string', $method->invoke($grantMock));
|
||||
$this->assertIsString($method->invoke($grantMock));
|
||||
}
|
||||
|
||||
public function testCanRespondToAuthorizationRequest()
|
||||
@ -498,21 +469,21 @@ class AbstractGrantTest extends TestCase
|
||||
$this->assertFalse($grantMock->canRespondToAuthorizationRequest(new ServerRequest()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testValidateAuthorizationRequest()
|
||||
{
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grantMock->validateAuthorizationRequest(new ServerRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testCompleteAuthorizationRequest()
|
||||
{
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grantMock->completeAuthorizationRequest(new AuthorizationRequest());
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
||||
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
@ -44,17 +46,15 @@ class ClientCredentialsGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
|
||||
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||
@ -30,56 +31,47 @@ class ImplicitGrantTest extends TestCase
|
||||
*/
|
||||
protected $cryptStub;
|
||||
|
||||
public function setUp()
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->cryptStub = new CryptTraitStub();
|
||||
}
|
||||
|
||||
public function testGetIdentifier()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$this->assertEquals('implicit', $grant->getIdentifier());
|
||||
}
|
||||
|
||||
public function testCanRespondToAccessTokenRequest()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$this->assertFalse(
|
||||
$grant->canRespondToAccessTokenRequest(new ServerRequest())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testRespondToAccessTokenRequest()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grant->respondToAccessTokenRequest(
|
||||
new ServerRequest(),
|
||||
new StubResponseType(),
|
||||
new \DateInterval('PT10M')
|
||||
new DateInterval('PT10M')
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanRespondToAuthorizationRequest()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'token',
|
||||
'client_id' => 'foo',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'token',
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
$this->assertTrue($grant->canRespondToAuthorizationRequest($request));
|
||||
}
|
||||
@ -95,25 +87,16 @@ class ImplicitGrantTest extends TestCase
|
||||
$scopeEntity = new ScopeEntity();
|
||||
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||
}
|
||||
@ -129,89 +112,54 @@ class ImplicitGrantTest extends TestCase
|
||||
$scopeEntity = new ScopeEntity();
|
||||
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
*/
|
||||
public function testValidateAuthorizationRequestMissingClientId()
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams(['response_type' => 'code']);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(3);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 4
|
||||
*/
|
||||
public function testValidateAuthorizationRequestInvalidClientId()
|
||||
{
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn(null);
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
]);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(4);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 4
|
||||
*/
|
||||
public function testValidateAuthorizationRequestBadRedirectUriString()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -219,31 +167,21 @@ class ImplicitGrantTest extends TestCase
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar',
|
||||
]);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(4);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 4
|
||||
*/
|
||||
public function testValidateAuthorizationRequestBadRedirectUriArray()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -251,37 +189,37 @@ class ImplicitGrantTest extends TestCase
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar',
|
||||
]
|
||||
);
|
||||
$request = (new ServerRequest())->withQueryParams([
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://bar',
|
||||
]);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(4);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
public function testCompleteAuthorizationRequest()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setIdentifier('identifier');
|
||||
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setClient($client);
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setClient($client);
|
||||
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn($accessToken);
|
||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||
|
||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||
@ -295,10 +233,6 @@ class ImplicitGrantTest extends TestCase
|
||||
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 9
|
||||
*/
|
||||
public function testCompleteAuthorizationRequestDenied()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
@ -319,20 +253,29 @@ class ImplicitGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(9);
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
|
||||
public function testAccessTokenRepositoryUniqueConstraintCheck()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setIdentifier('identifier');
|
||||
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setClient($client);
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setClient($client);
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn($accessToken);
|
||||
$accessTokenRepositoryMock->expects($this->at(0))->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
$accessTokenRepositoryMock->expects($this->at(1))->method('persistNewAccessToken')->willReturnSelf();
|
||||
|
||||
@ -347,10 +290,6 @@ class ImplicitGrantTest extends TestCase
|
||||
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 7
|
||||
*/
|
||||
public function testAccessTokenRepositoryFailToPersist()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
@ -359,7 +298,7 @@ class ImplicitGrantTest extends TestCase
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||
@ -372,13 +311,12 @@ class ImplicitGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(7);
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||
* @expectedExceptionCode 100
|
||||
*/
|
||||
public function testAccessTokenRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
@ -387,7 +325,7 @@ class ImplicitGrantTest extends TestCase
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
@ -400,34 +338,38 @@ class ImplicitGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException::class);
|
||||
$this->expectExceptionCode(100);
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testSetRefreshTokenTTL()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant->setRefreshTokenTTL(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grant->setRefreshTokenTTL(new DateInterval('PT10M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testSetRefreshTokenRepository()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testCompleteAuthorizationRequestNoUser()
|
||||
{
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant = new ImplicitGrant(new DateInterval('PT10M'));
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
$grant->completeAuthorizationRequest(new AuthorizationRequest());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
@ -60,19 +62,17 @@ class PasswordGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
|
||||
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||
@ -105,16 +105,14 @@ class PasswordGrantTest extends TestCase
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
@ -123,9 +121,6 @@ class PasswordGrantTest extends TestCase
|
||||
$this->assertNull($responseType->getRefreshToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testRespondToRequestMissingUsername()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -142,21 +137,18 @@ class PasswordGrantTest extends TestCase
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withQueryParams([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testRespondToRequestMissingPassword()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -173,22 +165,19 @@ class PasswordGrantTest extends TestCase
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'alex',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'alex',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function testRespondToRequestBadCredentials()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -206,17 +195,18 @@ class PasswordGrantTest extends TestCase
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'alex',
|
||||
'password' => 'whisky',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'username' => 'alex',
|
||||
'password' => 'whisky',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(10);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
@ -26,7 +27,7 @@ class RefreshTokenGrantTest extends TestCase
|
||||
*/
|
||||
protected $cryptStub;
|
||||
|
||||
public function setUp()
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->cryptStub = new CryptTraitStub();
|
||||
}
|
||||
@ -79,8 +80,7 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
@ -88,7 +88,7 @@ class RefreshTokenGrantTest extends TestCase
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
|
||||
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||
@ -136,8 +136,7 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody([
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
@ -191,27 +190,20 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
'scope' => 'foo',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
'scope' => 'foo',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
|
||||
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 5
|
||||
*/
|
||||
public function testRespondToUnexpectedScope()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -250,24 +242,21 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
'scope' => 'foobar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
'scope' => 'foobar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(5);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
*/
|
||||
public function testRespondToRequestMissingOldToken()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -284,22 +273,19 @@ class RefreshTokenGrantTest extends TestCase
|
||||
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(3);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 8
|
||||
*/
|
||||
public function testRespondToRequestInvalidOldToken()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -318,23 +304,20 @@ class RefreshTokenGrantTest extends TestCase
|
||||
|
||||
$oldRefreshToken = 'foobar';
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(8);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 8
|
||||
*/
|
||||
public function testRespondToRequestClientMismatch()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -367,23 +350,20 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(8);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 8
|
||||
*/
|
||||
public function testRespondToRequestExpiredToken()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -413,23 +393,20 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(8);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 8
|
||||
*/
|
||||
public function testRespondToRequestRevokedToken()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@ -460,16 +437,17 @@ class RefreshTokenGrantTest extends TestCase
|
||||
)
|
||||
);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withParsedBody(
|
||||
[
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]
|
||||
);
|
||||
$serverRequest = (new ServerRequest())->withParsedBody([
|
||||
'client_id' => 'foo',
|
||||
'client_secret' => 'bar',
|
||||
'refresh_token' => $oldRefreshToken,
|
||||
]);
|
||||
|
||||
$responseType = new StubResponseType();
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||
|
||||
$this->expectException(\League\OAuth2\Server\Exception\OAuthServerException::class);
|
||||
$this->expectExceptionCode(8);
|
||||
|
||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace LeagueTests\Middleware;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
@ -66,7 +67,7 @@ class AuthorizationServerMiddlewareTest extends TestCase
|
||||
public function testOAuthErrorResponse()
|
||||
{
|
||||
$clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepository->method('getClientEntity')->willReturn(null);
|
||||
$clientRepository->method('validateClient')->willReturn(false);
|
||||
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
@ -77,7 +78,7 @@ class AuthorizationServerMiddlewareTest extends TestCase
|
||||
new StubResponseType()
|
||||
);
|
||||
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M'));
|
||||
$server->enableGrantType(new ClientCredentialsGrant(), new DateInterval('PT1M'));
|
||||
|
||||
$_POST['grant_type'] = 'client_credentials';
|
||||
$_POST['client_id'] = 'foo';
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace LeagueTests\Middleware;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
@ -27,13 +29,13 @@ class ResourceServerMiddlewareTest extends TestCase
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('test');
|
||||
$accessToken->setUserIdentifier(123);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$token = $accessToken->convertToJWT(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$token = (string) $accessToken;
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $token));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $token));
|
||||
|
||||
$middleware = new ResourceServerMiddleware($server);
|
||||
$response = $middleware->__invoke(
|
||||
@ -62,13 +64,13 @@ class ResourceServerMiddlewareTest extends TestCase
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('test');
|
||||
$accessToken->setUserIdentifier(123);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->sub(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->sub(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$token = $accessToken->convertToJWT(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$token = (string) $accessToken;
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $token));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $token));
|
||||
|
||||
$middleware = new ResourceServerMiddleware($server);
|
||||
$response = $middleware->__invoke(
|
||||
@ -91,8 +93,7 @@ class ResourceServerMiddlewareTest extends TestCase
|
||||
'file://' . __DIR__ . '/../Stubs/public.key'
|
||||
);
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', '');
|
||||
$request = (new ServerRequest())->withHeader('authorization', '');
|
||||
|
||||
$middleware = new ResourceServerMiddleware($server);
|
||||
$response = $middleware->__invoke(
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace LeagueTests\ResponseTypes;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
@ -32,14 +34,15 @@ class BearerResponseTypeTest extends TestCase
|
||||
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('abcdef');
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->addScope($scope);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier('abcdef');
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
@ -54,7 +57,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
|
||||
$response->getBody()->rewind();
|
||||
$json = json_decode($response->getBody()->getContents());
|
||||
$this->assertAttributeEquals('Bearer', 'token_type', $json);
|
||||
$this->assertEquals('Bearer', $json->token_type);
|
||||
$this->assertObjectHasAttribute('expires_in', $json);
|
||||
$this->assertObjectHasAttribute('access_token', $json);
|
||||
$this->assertObjectHasAttribute('refresh_token', $json);
|
||||
@ -74,14 +77,15 @@ class BearerResponseTypeTest extends TestCase
|
||||
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('abcdef');
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->addScope($scope);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier('abcdef');
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
@ -96,13 +100,13 @@ class BearerResponseTypeTest extends TestCase
|
||||
|
||||
$response->getBody()->rewind();
|
||||
$json = json_decode($response->getBody()->getContents());
|
||||
$this->assertAttributeEquals('Bearer', 'token_type', $json);
|
||||
$this->assertEquals('Bearer', $json->token_type);
|
||||
$this->assertObjectHasAttribute('expires_in', $json);
|
||||
$this->assertObjectHasAttribute('access_token', $json);
|
||||
$this->assertObjectHasAttribute('refresh_token', $json);
|
||||
|
||||
$this->assertObjectHasAttribute('foo', $json);
|
||||
$this->assertAttributeEquals('bar', 'foo', $json);
|
||||
$this->assertEquals('bar', $json->foo);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderValidToken()
|
||||
@ -117,13 +121,14 @@ class BearerResponseTypeTest extends TestCase
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('abcdef');
|
||||
$accessToken->setUserIdentifier(123);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier('abcdef');
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
@ -137,8 +142,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $json->access_token));
|
||||
|
||||
$request = $authorizationValidator->validateAuthorization($request);
|
||||
|
||||
@ -162,13 +166,14 @@ class BearerResponseTypeTest extends TestCase
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('abcdef');
|
||||
$accessToken->setUserIdentifier(123);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier('abcdef');
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
@ -179,8 +184,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo'));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo'));
|
||||
|
||||
try {
|
||||
$authorizationValidator->validateAuthorization($request);
|
||||
@ -204,13 +208,14 @@ class BearerResponseTypeTest extends TestCase
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier('abcdef');
|
||||
$accessToken->setUserIdentifier(123);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier('abcdef');
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H')));
|
||||
$refreshToken->setExpiryDateTime((new DateTimeImmutable())->add(new DateInterval('PT1H')));
|
||||
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
@ -224,8 +229,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token));
|
||||
$request = (new ServerRequest())->withHeader('authorization', sprintf('Bearer %s', $json->access_token));
|
||||
|
||||
try {
|
||||
$authorizationValidator->validateAuthorization($request);
|
||||
@ -248,8 +252,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', 'Bearer blah');
|
||||
$request = (new ServerRequest())->withHeader('authorization', 'Bearer blah');
|
||||
|
||||
try {
|
||||
$authorizationValidator->validateAuthorization($request);
|
||||
@ -272,8 +275,7 @@ class BearerResponseTypeTest extends TestCase
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', 'Bearer blah.blah.blah');
|
||||
$request = (new ServerRequest())->withHeader('authorization', 'Bearer blah.blah.blah');
|
||||
|
||||
try {
|
||||
$authorizationValidator->validateAuthorization($request);
|
||||
|
@ -15,8 +15,8 @@ class ClientEntity implements ClientEntityInterface
|
||||
$this->redirectUri = $uri;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
public function setConfidential()
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->isConfidential = true;
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,10 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CryptKeyTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testNoFile()
|
||||
{
|
||||
$this->expectException(\LogicException::class);
|
||||
|
||||
new CryptKey('undefined file');
|
||||
}
|
||||
|
||||
@ -27,6 +26,11 @@ class CryptKeyTest extends TestCase
|
||||
public function testKeyFileCreation()
|
||||
{
|
||||
$keyContent = file_get_contents(__DIR__ . '/../Stubs/public.key');
|
||||
|
||||
if (!is_string($keyContent)) {
|
||||
$this->fail('The public key stub is not a string');
|
||||
}
|
||||
|
||||
$key = new CryptKey($keyContent);
|
||||
|
||||
$this->assertEquals(
|
||||
@ -35,6 +39,11 @@ class CryptKeyTest extends TestCase
|
||||
);
|
||||
|
||||
$keyContent = file_get_contents(__DIR__ . '/../Stubs/private.key.crlf');
|
||||
|
||||
if (!is_string($keyContent)) {
|
||||
$this->fail('The private key (crlf) stub is not a string');
|
||||
}
|
||||
|
||||
$key = new CryptKey($keyContent);
|
||||
|
||||
$this->assertEquals(
|
||||
|
@ -10,7 +10,7 @@ class CryptTraitTest extends TestCase
|
||||
{
|
||||
protected $cryptStub;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->cryptStub = new CryptTraitStub();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user