mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-22 21:19:46 +05:30
Merge remote-tracking branch 'upstream/master' into exception-has-redirect
This commit is contained in:
commit
466e1a639d
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -11,3 +11,4 @@
|
|||||||
/CHANGELOG.md export-ignore
|
/CHANGELOG.md export-ignore
|
||||||
/CONTRIBUTING.md export-ignore
|
/CONTRIBUTING.md export-ignore
|
||||||
/README.md export-ignore
|
/README.md export-ignore
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ enabled:
|
|||||||
- phpdoc_inline_tag
|
- phpdoc_inline_tag
|
||||||
- phpdoc_no_access
|
- phpdoc_no_access
|
||||||
- phpdoc_no_simplified_null_return
|
- phpdoc_no_simplified_null_return
|
||||||
- phpdoc_order
|
|
||||||
- phpdoc_property
|
- phpdoc_property
|
||||||
- phpdoc_scalar
|
- phpdoc_scalar
|
||||||
- phpdoc_separation
|
- phpdoc_separation
|
||||||
|
19
.travis.yml
19
.travis.yml
@ -1,24 +1,31 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
|
dist: trusty
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- vendor
|
- vendor
|
||||||
|
|
||||||
|
env:
|
||||||
|
- DEPENDENCIES=""
|
||||||
|
- DEPENDENCIES="--prefer-lowest --prefer-stable"
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.5.9
|
|
||||||
- 5.5
|
|
||||||
- 5.6
|
|
||||||
- 7.0
|
- 7.0
|
||||||
- 7.1
|
- 7.1
|
||||||
- hhvm
|
- 7.2
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- travis_retry composer install --no-interaction --prefer-source
|
- composer update --no-interaction --prefer-dist $DEPENDENCIES
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- vendor/bin/phpunit
|
- vendor/bin/phpunit --coverage-clover=coverage.clover
|
||||||
|
- vendor/bin/phpstan analyse -l 7 -c phpstan.neon src tests
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- wget https://scrutinizer-ci.com/ocular.phar
|
||||||
|
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
585
CHANGELOG.md
585
CHANGELOG.md
@ -1,325 +1,446 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## 5.1.3 (released 2016-10-12)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
* Fixed WWW-Authenticate header (Issue #669)
|
## [Unreleased]
|
||||||
* Increase the recommended RSA key length from 1024 to 2048 bits (Issue #668)
|
|
||||||
|
|
||||||
## 5.1.2 (released 2016-09-19)
|
### Fixed
|
||||||
|
- Catch and handle `BadMethodCallException` from the `verify()` method of the JWT token in the `validateAuthorization` method (PR #904)
|
||||||
|
|
||||||
* Fixed `finalizeScopes` call (Issue #650)
|
## [7.1.1] - released 2018-05-21
|
||||||
|
|
||||||
## 5.1.1 (released 2016-07-26)
|
### Fixed
|
||||||
|
- No longer set a WWW-Authenticate header for invalid clients if the client did not send an Authorization header in the original request (PR #902)
|
||||||
|
|
||||||
* Improved test suite (Issue #614)
|
## [7.1.0] - released 2018-04-22
|
||||||
* Updated docblocks (Issue #616)
|
|
||||||
* Replace `array_shift` with `foreach` loop (Issue #621)
|
|
||||||
* Allow easy addition of custom fields to Bearer token response (Issue #624)
|
|
||||||
* Key file auto-generation from string (Issue #625)
|
|
||||||
|
|
||||||
## 5.1.0 (released 2016-06-28)
|
### Changed
|
||||||
|
- Changed hint for unsupportedGrantType exception so it no longer references the grant type parameter which isn't always expected (PR #893)
|
||||||
|
- Upgrade PHPStan checks to level 7 (PR #856)
|
||||||
|
|
||||||
* Implemented RFC7636 (Issue #574)
|
### Added
|
||||||
* Unify middleware exception responses (Issue #578)
|
- Added event emitters for issued access and refresh tokens (PR #860)
|
||||||
* Updated examples (Issue #589)
|
- Can now use Defuse\Crypto\Key for encryption/decryption of keys which is faster than the Cryto class (PR #812)
|
||||||
* Ensure state is in access denied redirect (Issue #597)
|
|
||||||
* Remove redundant `isExpired()` method from entity interfaces and traits (Issue #600)
|
|
||||||
* Added a check for unique access token constraint violation (Issue #601)
|
|
||||||
* Look at Authorization header directly for HTTP Basic auth checks (Issue #604)
|
|
||||||
* Added catch Runtime exception when parsing JWT string (Issue #605)
|
|
||||||
* Allow `paragonie/random_compat` 2.x (Issue #606)
|
|
||||||
* Added `indigophp/hash-compat` to Composer suggestions and `require-dev` for PHP 5.5 support
|
|
||||||
|
|
||||||
## 5.0.3 (released 2016-05-04)
|
### Removed
|
||||||
|
- Remove paragone/random_compat from dependencies
|
||||||
|
|
||||||
* Fix hints in PasswordGrant (Issue #560)
|
## [7.0.0] - released 2018-02-18
|
||||||
* Add meaning of `Resource owner` to terminology.md (Issue #561)
|
|
||||||
* Use constant for event name instead of explicit string (Issue #563)
|
|
||||||
* Remove unused request property (Issue #564)
|
|
||||||
* Correct wrong phpdoc (Issue #569)
|
|
||||||
* Fixed typo in exception string (Issue #570)
|
|
||||||
|
|
||||||
## 5.0.2 (released 2016-04-18)
|
### Added
|
||||||
|
- Use PHPStan for static analysis of code (PR #848)
|
||||||
|
- Enforce stricter static analysis checks and upgrade library dependencies (PR #852)
|
||||||
|
- Provide PHPStan coverage for tests and update PHPUnit (PR #849)
|
||||||
|
- Get and set methods for OAuth Server Exception payloads. Allow implementer to specify the JSON encode options (PR #719)
|
||||||
|
|
||||||
* `state` parameter is now correctly returned after implicit grant authorization
|
### Changed
|
||||||
* Small code and docblock improvements
|
- ClientRepository interface will now accept null for the Grant type to improve extensibility options (PR #607)
|
||||||
|
- Do not issue an error if key file permissions are 400 or 440 (PR #839)
|
||||||
|
- Skip key file creation if the file already exists (PR #845)
|
||||||
|
- Change changelog format and update readme
|
||||||
|
|
||||||
## 5.0.1 (released 2016-04-18)
|
### Removed
|
||||||
|
- Support for PHP 5.6
|
||||||
|
- Support for version 5.x and 6.x of the library
|
||||||
|
|
||||||
* Fixes an issue (#550) whereby it was unclear whether or not to validate a client's secret during a request.
|
### Fixed
|
||||||
|
- PKCE implementation (PR #744)
|
||||||
|
- Set correct redirect URI when validating scopes (PR #840)
|
||||||
|
- S256 code challenege method (PR #842)
|
||||||
|
- Accept RSA key with CRLF line endings (PR #805)
|
||||||
|
|
||||||
## 5.0.0 (released 2016-04-17)
|
## [6.1.1] - 2017-12-23
|
||||||
|
|
||||||
|
- Removed check on empty scopes
|
||||||
|
|
||||||
|
## [6.1.0] - 2017-12-23
|
||||||
|
|
||||||
|
- Changed the token type issued by the Implicit Grant to be Bearer instead of bearer. (PR #724)
|
||||||
|
- Replaced call to array_key_exists() with the faster isset() on the Implicit Grant. (PR #749)
|
||||||
|
- Allow specification of query delimiter character in the Password Grant (PR #801)
|
||||||
|
- Add Zend Diactoros library dependency to examples (PR #678)
|
||||||
|
- Can set default scope for the authorization endpoint. If no scope is passed during an authorization request, the default scope will be used if set. If not, the server will issue an invalid scope exception (PR #811)
|
||||||
|
- Added validation for redirect URIs on the authorization end point to ensure exactly one redirection URI has been passed (PR #573)
|
||||||
|
|
||||||
|
## [6.0.2] - 2017-08-03
|
||||||
|
|
||||||
|
- An invalid refresh token that can't be decrypted now returns a HTTP 401 error instead of HTTP 400 (Issue #759)
|
||||||
|
- Removed chmod from CryptKey and add toggle to disable checking (Issue #776)
|
||||||
|
- Fixes invalid code challenge method payload key name (Issue #777)
|
||||||
|
|
||||||
|
## [6.0.1] - 2017-07-19
|
||||||
|
|
||||||
|
To address feedback from the security release the following change has been made:
|
||||||
|
|
||||||
|
- If an RSA key cannot be chmod'ed to 600 then it will now throw a E_USER_NOTICE instead of an exception.
|
||||||
|
|
||||||
|
## [6.0.0] - 2017-07-01
|
||||||
|
|
||||||
|
- Breaking change: The `AuthorizationServer` constructor now expects an encryption key string instead of a public key
|
||||||
|
- Remove support for HHVM
|
||||||
|
- Remove support for PHP 5.5
|
||||||
|
|
||||||
|
## [5.1.4] - 2017-07-01
|
||||||
|
|
||||||
|
- Fixed multiple security vulnerabilities as a result of a security audit paid for by the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source). All users of this library are encouraged to update as soon as possible to this version or version 6.0 or greater.
|
||||||
|
- It is recommended on each `AuthorizationServer` instance you set the `setEncryptionKey()`. This will result in stronger encryption being used. If this method is not set messages will be sent to the defined error handling routines (using `error_log`). Please see the examples and documentation for examples.
|
||||||
|
- TravisCI now tests PHP 7.1 (Issue #671)
|
||||||
|
- Fix middleware example fatal error (Issue #682)
|
||||||
|
- Fix typo in the first README sentence (Issue #690)
|
||||||
|
- Corrected DateInterval from 1 min to 1 month (Issue #709)
|
||||||
|
|
||||||
|
## [5.1.3] - 2016-10-12
|
||||||
|
|
||||||
|
- Fixed WWW-Authenticate header (Issue #669)
|
||||||
|
- Increase the recommended RSA key length from 1024 to 2048 bits (Issue #668)
|
||||||
|
|
||||||
|
## [5.1.2] - 2016-09-19
|
||||||
|
|
||||||
|
- Fixed `finalizeScopes` call (Issue #650)
|
||||||
|
|
||||||
|
## [5.1.1] - 2016-07-26
|
||||||
|
|
||||||
|
- Improved test suite (Issue #614)
|
||||||
|
- Updated docblocks (Issue #616)
|
||||||
|
- Replace `array_shift` with `foreach` loop (Issue #621)
|
||||||
|
- Allow easy addition of custom fields to Bearer token response (Issue #624)
|
||||||
|
- Key file auto-generation from string (Issue #625)
|
||||||
|
|
||||||
|
## [5.1.0] - 2016-06-28
|
||||||
|
|
||||||
|
- Implemented RFC7636 (Issue #574)
|
||||||
|
- Unify middleware exception responses (Issue #578)
|
||||||
|
- Updated examples (Issue #589)
|
||||||
|
- Ensure state is in access denied redirect (Issue #597)
|
||||||
|
- Remove redundant `isExpired()` method from entity interfaces and traits (Issue #600)
|
||||||
|
- Added a check for unique access token constraint violation (Issue #601)
|
||||||
|
- Look at Authorization header directly for HTTP Basic auth checks (Issue #604)
|
||||||
|
- Added catch Runtime exception when parsing JWT string (Issue #605)
|
||||||
|
- Allow `paragonie/random_compat` 2.x (Issue #606)
|
||||||
|
- Added `indigophp/hash-compat` to Composer suggestions and `require-dev` for PHP 5.5 support
|
||||||
|
|
||||||
|
## [5.0.3] - 2016-05-04
|
||||||
|
|
||||||
|
- Fix hints in PasswordGrant (Issue #560)
|
||||||
|
- Add meaning of `Resource owner` to terminology.md (Issue #561)
|
||||||
|
- Use constant for event name instead of explicit string (Issue #563)
|
||||||
|
- Remove unused request property (Issue #564)
|
||||||
|
- Correct wrong phpdoc (Issue #569)
|
||||||
|
- Fixed typo in exception string (Issue #570)
|
||||||
|
|
||||||
|
## [5.0.2] - 2016-04-18
|
||||||
|
|
||||||
|
- `state` parameter is now correctly returned after implicit grant authorization
|
||||||
|
- Small code and docblock improvements
|
||||||
|
|
||||||
|
## [5.0.1] - 2016-04-18
|
||||||
|
|
||||||
|
- Fixes an issue (#550) whereby it was unclear whether or not to validate a client's secret during a request.
|
||||||
|
|
||||||
|
## [5.0.0] - 2016-04-17
|
||||||
|
|
||||||
Version 5 is a complete code rewrite.
|
Version 5 is a complete code rewrite.
|
||||||
|
|
||||||
* JWT support
|
- Renamed Server class to AuthorizationServer
|
||||||
* PSR-7 support
|
- Added ResourceServer class
|
||||||
* Improved exception errors
|
- Run unit tests again PHP 5.5.9 as it's the minimum supported version
|
||||||
* Replace all occurrences of the term "Storage" with "Repository"
|
- Enable PHPUnit 5.0 support
|
||||||
* Simplify repositories
|
- Improved examples and documentation
|
||||||
* Entities conform to interfaces and use traits
|
- Make it clearer that the implicit grant doesn't support refresh tokens
|
||||||
* Auth code grant updated
|
- Improved refresh token validation errors
|
||||||
* Allow support for public clients
|
- Fixed refresh token expiry date
|
||||||
* Add support for #439
|
|
||||||
* Client credentials grant updated
|
|
||||||
* Password grant updated
|
|
||||||
* Allow support for public clients
|
|
||||||
* Refresh token grant updated
|
|
||||||
* Implement Implicit grant
|
|
||||||
* Bearer token output type
|
|
||||||
* Remove MAC token output type
|
|
||||||
* Authorization server rewrite
|
|
||||||
* Resource server class moved to PSR-7 middleware
|
|
||||||
* Tests
|
|
||||||
* Much much better documentation
|
|
||||||
|
|
||||||
Changes since RC2:
|
## [5.0.0-RC2] - 2016-04-10
|
||||||
|
|
||||||
* Renamed Server class to AuthorizationServer
|
- Allow multiple client redirect URIs (Issue #511)
|
||||||
* Added ResourceServer class
|
- Remove unused mac token interface (Issue #503)
|
||||||
* Run unit tests again PHP 5.5.9 as it's the minimum supported version
|
- Handle RSA key passphrase (Issue #502)
|
||||||
* Enable PHPUnit 5.0 support
|
- Remove access token repository from response types (Issue #501)
|
||||||
* Improved examples and documentation
|
- Remove unnecessary methods from entity interfaces (Issue #490)
|
||||||
* Make it clearer that the implicit grant doesn't support refresh tokens
|
- Ensure incoming JWT hasn't expired (Issue #509)
|
||||||
* Improved refresh token validation errors
|
- Fix client identifier passed where user identifier is expected (Issue #498)
|
||||||
* Fixed refresh token expiry date
|
- Removed built-in entities; added traits to for quick re-use (Issue #504)
|
||||||
|
- Redirect uri is required only if the "redirect_uri" parameter was included in the authorization request (Issue #514)
|
||||||
|
- Removed templating for auth code and implicit grants (Issue #499)
|
||||||
|
|
||||||
## 5.0.0-RC2 (released 2016-04-10)
|
## [5.0.0-RC1] - 2016-03-24
|
||||||
|
|
||||||
Changes since RC1:
|
|
||||||
|
|
||||||
* Allow multiple client redirect URIs (Issue #511)
|
|
||||||
* Remove unused mac token interface (Issue #503)
|
|
||||||
* Handle RSA key passphrase (Issue #502)
|
|
||||||
* Remove access token repository from response types (Issue #501)
|
|
||||||
* Remove unnecessary methods from entity interfaces (Issue #490)
|
|
||||||
* Ensure incoming JWT hasn't expired (Issue #509)
|
|
||||||
* Fix client identifier passed where user identifier is expected (Issue #498)
|
|
||||||
* Removed built-in entities; added traits to for quick re-use (Issue #504)
|
|
||||||
* Redirect uri is required only if the "redirect_uri" parameter was included in the authorization request (Issue #514)
|
|
||||||
* Removed templating for auth code and implicit grants (Issue #499)
|
|
||||||
|
|
||||||
## 5.0.0-RC1 (release 2016-03-24)
|
|
||||||
|
|
||||||
Version 5 is a complete code rewrite.
|
Version 5 is a complete code rewrite.
|
||||||
|
|
||||||
* JWT support
|
- JWT support
|
||||||
* PSR-7 support
|
- PSR-7 support
|
||||||
* Improved exception errors
|
- Improved exception errors
|
||||||
* Replace all occurrences of the term "Storage" with "Repository"
|
- Replace all occurrences of the term "Storage" with "Repository"
|
||||||
* Simplify repositories
|
- Simplify repositories
|
||||||
* Entities conform to interfaces and use traits
|
- Entities conform to interfaces and use traits
|
||||||
* Auth code grant updated
|
- Auth code grant updated
|
||||||
* Allow support for public clients
|
- Allow support for public clients
|
||||||
* Add support for #439
|
- Add support for #439
|
||||||
* Client credentials grant updated
|
- Client credentials grant updated
|
||||||
* Password grant updated
|
- Password grant updated
|
||||||
* Allow support for public clients
|
- Allow support for public clients
|
||||||
* Refresh token grant updated
|
- Refresh token grant updated
|
||||||
* Implement Implicit grant
|
- Implement Implicit grant
|
||||||
* Bearer token output type
|
- Bearer token output type
|
||||||
* Remove MAC token output type
|
- Remove MAC token output type
|
||||||
* Authorization server rewrite
|
- Authorization server rewrite
|
||||||
* Resource server class moved to PSR-7 middleware
|
- Resource server class moved to PSR-7 middleware
|
||||||
* Tests
|
- Tests
|
||||||
* Much much better documentation
|
- Much much better documentation
|
||||||
|
|
||||||
## 4.1.5 (released 2016-01-04)
|
## [4.1.5] - 2016-01-04
|
||||||
|
|
||||||
* Enable Symfony 3.0 support (#412)
|
- Enable Symfony 3.0 support (#412)
|
||||||
|
|
||||||
## 4.1.4 (released 2015-11-13)
|
## [4.1.4] - 2015-11-13
|
||||||
|
|
||||||
* Fix for determining access token in header (Issue #328)
|
- Fix for determining access token in header (Issue #328)
|
||||||
* Refresh tokens are now returned for MAC responses (Issue #356)
|
- Refresh tokens are now returned for MAC responses (Issue #356)
|
||||||
* Added integration list to readme (Issue #341)
|
- Added integration list to readme (Issue #341)
|
||||||
* Expose parameter passed to exceptions (Issue #345)
|
- Expose parameter passed to exceptions (Issue #345)
|
||||||
* Removed duplicate routing setup code (Issue #346)
|
- Removed duplicate routing setup code (Issue #346)
|
||||||
* Docs fix (Issues #347, #360, #380)
|
- Docs fix (Issues #347, #360, #380)
|
||||||
* Examples fix (Issues #348, #358)
|
- Examples fix (Issues #348, #358)
|
||||||
* Fix typo in docblock (Issue #352)
|
- Fix typo in docblock (Issue #352)
|
||||||
* Improved timeouts for MAC tokens (Issue #364)
|
- Improved timeouts for MAC tokens (Issue #364)
|
||||||
* `hash_hmac()` should output raw binary data, not hexits (Issue #370)
|
- `hash_hmac()` should output raw binary data, not hexits (Issue #370)
|
||||||
* Improved regex for matching all Base64 characters (Issue #371)
|
- Improved regex for matching all Base64 characters (Issue #371)
|
||||||
* Fix incorrect signature parameter (Issue #372)
|
- Fix incorrect signature parameter (Issue #372)
|
||||||
* AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377)
|
- AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377)
|
||||||
* Added priority argument to event listener (Issue #388)
|
- Added priority argument to event listener (Issue #388)
|
||||||
|
|
||||||
## 4.1.3 (released 2015-03-22)
|
## [4.1.3] - 2015-03-22
|
||||||
|
|
||||||
* Docblock, namespace and inconsistency fixes (Issue #303)
|
- Docblock, namespace and inconsistency fixes (Issue #303)
|
||||||
* Docblock type fix (Issue #310)
|
- Docblock type fix (Issue #310)
|
||||||
* Example bug fix (Issue #300)
|
- Example bug fix (Issue #300)
|
||||||
* Updated league/event to ~2.1 (Issue #311)
|
- Updated league/event to ~2.1 (Issue #311)
|
||||||
* Fixed missing session scope (Issue #319)
|
- Fixed missing session scope (Issue #319)
|
||||||
* Updated interface docs (Issue #323)
|
- Updated interface docs (Issue #323)
|
||||||
* `.travis.yml` updates
|
- `.travis.yml` updates
|
||||||
|
|
||||||
## 4.1.2 (released 2015-01-01)
|
## [4.1.2] - 2015-01-01
|
||||||
|
|
||||||
* Remove side-effects in hash_equals() implementation (Issue #290)
|
- Remove side-effects in hash_equals() implementation (Issue #290)
|
||||||
|
|
||||||
## 4.1.1 (released 2014-12-31)
|
## [4.1.1] - 2014-12-31
|
||||||
|
|
||||||
* Changed `symfony/http-foundation` dependency version to `~2.4` so package can be installed in Laravel `4.1.*`
|
- Changed `symfony/http-foundation` dependency version to `~2.4` so package can be installed in Laravel `4.1.*`
|
||||||
|
|
||||||
## 4.1.0 (released 2014-12-27)
|
## [4.1.0] - 2014-12-27
|
||||||
|
|
||||||
* Added MAC token support (Issue #158)
|
- Added MAC token support (Issue #158)
|
||||||
* Fixed example init code (Issue #280)
|
- Fixed example init code (Issue #280)
|
||||||
* Toggle refresh token rotation (Issue #286)
|
- Toggle refresh token rotation (Issue #286)
|
||||||
* Docblock fixes
|
- Docblock fixes
|
||||||
|
|
||||||
## 4.0.5 (released 2014-12-15)
|
## [4.0.5] - 2014-12-15
|
||||||
|
|
||||||
* Prevent duplicate session in auth code grant (Issue #282)
|
- Prevent duplicate session in auth code grant (Issue #282)
|
||||||
|
|
||||||
## 4.0.4 (released 2014-12-03)
|
## [4.0.4] - 2014-12-03
|
||||||
|
|
||||||
* Ensure refresh token hasn't expired (Issue #270)
|
- Ensure refresh token hasn't expired (Issue #270)
|
||||||
|
|
||||||
## 4.0.3 (released 2014-12-02)
|
## [4.0.3] - 2014-12-02
|
||||||
|
|
||||||
* Fix bad type hintings (Issue #267)
|
- Fix bad type hintings (Issue #267)
|
||||||
* Do not forget to set the expire time (Issue #268)
|
- Do not forget to set the expire time (Issue #268)
|
||||||
|
|
||||||
## 4.0.2 (released 2014-11-21)
|
## [4.0.2] - 2014-11-21
|
||||||
|
|
||||||
* Improved interfaces (Issue #255)
|
- Improved interfaces (Issue #255)
|
||||||
* Learnt how to spell delimiter and so `getScopeDelimiter()` and `setScopeDelimiter()` methods have been renamed
|
- Learnt how to spell delimiter and so `getScopeDelimiter()` and `setScopeDelimiter()` methods have been renamed
|
||||||
* Docblock improvements (Issue #254)
|
- Docblock improvements (Issue #254)
|
||||||
|
|
||||||
## 4.0.1 (released 2014-11-09)
|
## [4.0.1] - 2014-11-09
|
||||||
|
|
||||||
* Alias the master branch in composer.json (Issue #243)
|
- Alias the master branch in composer.json (Issue #243)
|
||||||
* Numerous PHP CodeSniffer fixes (Issue #244)
|
- Numerous PHP CodeSniffer fixes (Issue #244)
|
||||||
* .travis.yml update (Issue #245)
|
- .travis.yml update (Issue #245)
|
||||||
* The getAccessToken method should return an AccessTokenEntity object instead of a string in ResourceServer.php (#246)
|
- The getAccessToken method should return an AccessTokenEntity object instead of a string in ResourceServer.php (#246)
|
||||||
|
|
||||||
## 4.0.0 (released 2014-11-08)
|
## [4.0.0] - 2014-11-08
|
||||||
|
|
||||||
* Complete rewrite
|
- Complete rewrite
|
||||||
* Check out the documentation - [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com)
|
- Check out the documentation - [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com)
|
||||||
|
|
||||||
## 3.2.0 (released 2014-04-16)
|
## [3.2.0] - 2014-04-16
|
||||||
|
|
||||||
* Added the ability to change the algorithm that is used to generate the token strings (Issue #151)
|
- Added the ability to change the algorithm that is used to generate the token strings (Issue #151)
|
||||||
|
|
||||||
## 3.1.2 (released 2014-02-26)
|
## [3.1.2] - 2014-02-26
|
||||||
|
|
||||||
* Support Authorization being an environment variable. [See more](http://fortrabbit.com/docs/essentials/quirks-and-constraints#authorization-header)
|
- Support Authorization being an environment variable. [See more](http://fortrabbit.com/docs/essentials/quirks-and-constraints#authorization-header)
|
||||||
|
|
||||||
## 3.1.1 (released 2013-12-05)
|
## [3.1.1] - 2013-12-05
|
||||||
|
|
||||||
* Normalize headers when `getallheaders()` is available (Issues #108 and #114)
|
- Normalize headers when `getallheaders()` is available (Issues #108 and #114)
|
||||||
|
|
||||||
## 3.1.0 (released 2013-12-05)
|
## [3.1.0] - 2013-12-05
|
||||||
|
|
||||||
* No longer necessary to inject the authorisation server into a grant, the server will inject itself
|
- No longer necessary to inject the authorisation server into a grant, the server will inject itself
|
||||||
* Added test for 1419ba8cdcf18dd034c8db9f7de86a2594b68605
|
- Added test for 1419ba8cdcf18dd034c8db9f7de86a2594b68605
|
||||||
|
|
||||||
## 3.0.1 (released 2013-12-02)
|
## [3.0.1] - 2013-12-02
|
||||||
|
|
||||||
* Forgot to tell TravisCI from testing PHP 5.3
|
- Forgot to tell TravisCI from testing PHP 5.3
|
||||||
|
|
||||||
## 3.0.0 (released 2013-12-02)
|
## [3.0.0] - 2013-12-02
|
||||||
|
|
||||||
* Fixed spelling of Implicit grant class (Issue #84)
|
- Fixed spelling of Implicit grant class (Issue #84)
|
||||||
* Travis CI now tests for PHP 5.5
|
- Travis CI now tests for PHP 5.5
|
||||||
* Fixes for checking headers for resource server (Issues #79 and #)
|
- Fixes for checking headers for resource server (Issues #79 and #)
|
||||||
* The word "bearer" now has a capital "B" in JSON output to match OAuth 2.0 spec
|
- The word "bearer" now has a capital "B" in JSON output to match OAuth 2.0 spec
|
||||||
* All grants no longer remove old sessions by default
|
- All grants no longer remove old sessions by default
|
||||||
* All grants now support custom access token TTL (Issue #92)
|
- All grants now support custom access token TTL (Issue #92)
|
||||||
* All methods which didn't before return a value now return `$this` to support method chaining
|
- All methods which didn't before return a value now return `$this` to support method chaining
|
||||||
* Removed the build in DB providers - these will be put in their own repos to remove baggage in the main repository
|
- Removed the build in DB providers - these will be put in their own repos to remove baggage in the main repository
|
||||||
* Removed support for PHP 5.3 because this library now uses traits and will use other modern PHP features going forward
|
- Removed support for PHP 5.3 because this library now uses traits and will use other modern PHP features going forward
|
||||||
* Moved some grant related functions into a trait to reduce duplicate code
|
- Moved some grant related functions into a trait to reduce duplicate code
|
||||||
|
|
||||||
## 2.1.1 (released 2013-06-02)
|
## [2.1.1] - 2013-06-02
|
||||||
|
|
||||||
* Added conditional `isValid()` flag to check for Authorization header only (thanks @alexmcroberts)
|
- Added conditional `isValid()` flag to check for Authorization header only (thanks @alexmcroberts)
|
||||||
* Fixed semantic meaning of `requireScopeParam()` and `requireStateParam()` by changing their default value to true
|
- Fixed semantic meaning of `requireScopeParam()` and `requireStateParam()` by changing their default value to true
|
||||||
* Updated some duff docblocks
|
- Updated some duff docblocks
|
||||||
* Corrected array key call in Resource.php (Issue #63)
|
- Corrected array key call in Resource.php (Issue #63)
|
||||||
|
|
||||||
## 2.1 (released 2013-05-10)
|
## [2.1.0] - 2013-05-10
|
||||||
|
|
||||||
* Moved zetacomponents/database to "suggest" in composer.json. If you rely on this feature you now need to include " zetacomponents/database" into "require" key in your own composer.json. (Issue #51)
|
- Moved zetacomponents/database to "suggest" in composer.json. If you rely on this feature you now need to include " zetacomponents/database" into "require" key in your own composer.json. (Issue #51)
|
||||||
* New method in Refresh grant called `rotateRefreshTokens()`. Pass in `true` to issue a new refresh token each time an access token is refreshed. This parameter needs to be set to true in order to request reduced scopes with the new access token. (Issue #47)
|
- New method in Refresh grant called `rotateRefreshTokens()`. Pass in `true` to issue a new refresh token each time an access token is refreshed. This parameter needs to be set to true in order to request reduced scopes with the new access token. (Issue #47)
|
||||||
* Rename `key` column in oauth_scopes table to `scope` as `key` is a reserved SQL word. (Issue #45)
|
- Rename `key` column in oauth_scopes table to `scope` as `key` is a reserved SQL word. (Issue #45)
|
||||||
* The `scope` parameter is no longer required by default as per the RFC. (Issue #43)
|
- The `scope` parameter is no longer required by default as per the RFC. (Issue #43)
|
||||||
* You can now set multiple default scopes by passing an array into `setDefaultScope()`. (Issue #42)
|
- You can now set multiple default scopes by passing an array into `setDefaultScope()`. (Issue #42)
|
||||||
* The password and client credentials grants now allow for multiple sessions per user. (Issue #32)
|
- The password and client credentials grants now allow for multiple sessions per user. (Issue #32)
|
||||||
* Scopes associated to authorization codes are not held in their own table (Issue #44)
|
- Scopes associated to authorization codes are not held in their own table (Issue #44)
|
||||||
* Database schema updates.
|
- Database schema updates.
|
||||||
|
|
||||||
## 2.0.5 (released 2013-05-09)
|
## [2.0.5] - 2013-05-09
|
||||||
|
|
||||||
* Fixed `oauth_session_token_scopes` table primary key
|
- Fixed `oauth_session_token_scopes` table primary key
|
||||||
* Removed `DEFAULT ''` that has slipped into some tables
|
- Removed `DEFAULT ''` that has slipped into some tables
|
||||||
* Fixed docblock for `SessionInterface::associateRefreshToken()`
|
- Fixed docblock for `SessionInterface::associateRefreshToken()`
|
||||||
|
|
||||||
## 2.0.4 (released 2013-05-09)
|
## [2.0.4] - 2013-05-09
|
||||||
|
|
||||||
* Renamed primary key in oauth_client_endpoints table
|
- Renamed primary key in oauth_client_endpoints table
|
||||||
* Adding missing column to oauth_session_authcodes
|
- Adding missing column to oauth_session_authcodes
|
||||||
* SECURITY FIX: A refresh token should be bound to a client ID
|
|
||||||
|
|
||||||
## 2.0.3 (released 2013-05-08)
|
### Security
|
||||||
|
- A refresh token should be bound to a client ID
|
||||||
|
|
||||||
* Fixed a link to code in composer.json
|
## [2.0.3] - 2013-05-08
|
||||||
|
|
||||||
## 2.0.2 (released 2013-05-08)
|
- Fixed a link to code in composer.json
|
||||||
|
|
||||||
* Updated README with wiki guides
|
## [2.0.2] - 2013-05-08
|
||||||
* Removed `null` as default parameters in some methods in the storage interfaces
|
|
||||||
* Fixed license copyright
|
|
||||||
|
|
||||||
## 2.0.0 (released 2013-05-08)
|
- Updated README with wiki guides
|
||||||
|
- Removed `null` as default parameters in some methods in the storage interfaces
|
||||||
|
- Fixed license copyright
|
||||||
|
|
||||||
|
## [2.0.0] - 2013-05-08
|
||||||
|
|
||||||
**If you're upgrading from v1.0.8 there are lots of breaking changes**
|
**If you're upgrading from v1.0.8 there are lots of breaking changes**
|
||||||
|
|
||||||
* Rewrote the session storage interface from scratch so methods are more obvious
|
- Rewrote the session storage interface from scratch so methods are more obvious
|
||||||
* Included a PDO driver which implements the storage interfaces so the library is more "get up and go"
|
- Included a PDO driver which implements the storage interfaces so the library is more "get up and go"
|
||||||
* Further normalised the database structure so all sessions no longer contain infomation related to authorization grant (which may or may not be enabled)
|
- Further normalised the database structure so all sessions no longer contain infomation related to authorization grant (which may or may not be enabled)
|
||||||
* A session can have multiple associated access tokens
|
- A session can have multiple associated access tokens
|
||||||
* Individual grants can have custom expire times for access tokens
|
- Individual grants can have custom expire times for access tokens
|
||||||
* Authorization codes now have a TTL of 10 minutes by default (can be manually set)
|
- Authorization codes now have a TTL of 10 minutes by default (can be manually set)
|
||||||
* Refresh tokens now have a TTL of one week by default (can be manually set)
|
- Refresh tokens now have a TTL of one week by default (can be manually set)
|
||||||
* The client credentials grant will no longer gives out refresh tokens as per the specification
|
- The client credentials grant will no longer gives out refresh tokens as per the specification
|
||||||
|
|
||||||
## 1.0.8 (released 2013-03-18)
|
## [1.0.8] - 2013-03-18
|
||||||
|
|
||||||
* Fixed check for required state parameter
|
- Fixed check for required state parameter
|
||||||
* Fixed check that user's credentials are correct in Password grant
|
- Fixed check that user's credentials are correct in Password grant
|
||||||
|
|
||||||
## 1.0.7 (released 2013-03-04)
|
## [1.0.7] - 2013-03-04
|
||||||
|
|
||||||
* Added method `requireStateParam()`
|
- Added method `requireStateParam()`
|
||||||
* Added method `requireScopeParam()`
|
- Added method `requireScopeParam()`
|
||||||
|
|
||||||
## 1.0.6 (released 2013-02-22)
|
## [1.0.6] - 2013-02-22
|
||||||
|
|
||||||
* Added links to tutorials in the README
|
- Added links to tutorials in the README
|
||||||
* Added missing `state` parameter request to the `checkAuthoriseParams()` method.
|
- Added missing `state` parameter request to the `checkAuthoriseParams()` method.
|
||||||
|
|
||||||
## 1.0.5 (released 2013-02-21)
|
## [1.0.5] - 2013-02-21
|
||||||
|
|
||||||
* Fixed the SQL example for SessionInterface::getScopes()
|
- Fixed the SQL example for SessionInterface::getScopes()
|
||||||
|
|
||||||
## 1.0.3 (released 2013-02-20)
|
## [1.0.3] - 2013-02-20
|
||||||
|
|
||||||
* Changed all instances of the "authentication server" to "authorization server"
|
- Changed all instances of the "authentication server" to "authorization server"
|
||||||
|
|
||||||
## 1.0.2 (released 2013-02-20)
|
## [1.0.2] - 2013-02-20
|
||||||
|
|
||||||
* Fixed MySQL create table order
|
- Fixed MySQL create table order
|
||||||
* Fixed version number in composer.json
|
- Fixed version number in composer.json
|
||||||
|
|
||||||
## 1.0.1 (released 2013-02-19)
|
## [1.0.1] - 2013-02-19
|
||||||
|
|
||||||
* Updated AuthServer.php to use `self::getParam()`
|
- Updated AuthServer.php to use `self::getParam()`
|
||||||
|
|
||||||
## 1.0.0 (released 2013-02-15)
|
## 1.0.0 - 2013-02-15
|
||||||
|
|
||||||
* First major release
|
- First major release
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/thephpleague/oauth2-server/compare/7.0.0...HEAD
|
||||||
|
[7.1.1]: https://github.com/thephpleague/oauth2-server/compare/7.1.0...7.1.1
|
||||||
|
[7.1.0]: https://github.com/thephpleague/oauth2-server/compare/7.0.0...7.1.0
|
||||||
|
[7.0.0]: https://github.com/thephpleague/oauth2-server/compare/6.1.1...7.0.0
|
||||||
|
[6.1.1]: https://github.com/thephpleague/oauth2-server/compare/6.0.0...6.1.1
|
||||||
|
[6.1.0]: https://github.com/thephpleague/oauth2-server/compare/6.0.2...6.1.0
|
||||||
|
[6.0.2]: https://github.com/thephpleague/oauth2-server/compare/6.0.1...6.0.2
|
||||||
|
[6.0.1]: https://github.com/thephpleague/oauth2-server/compare/6.0.0...6.0.1
|
||||||
|
[6.0.0]: https://github.com/thephpleague/oauth2-server/compare/5.1.4...6.0.0
|
||||||
|
[5.1.4]: https://github.com/thephpleague/oauth2-server/compare/5.1.3...5.1.4
|
||||||
|
[5.1.3]: https://github.com/thephpleague/oauth2-server/compare/5.1.2...5.1.3
|
||||||
|
[5.1.2]: https://github.com/thephpleague/oauth2-server/compare/5.1.1...5.1.2
|
||||||
|
[5.1.1]: https://github.com/thephpleague/oauth2-server/compare/5.1.0...5.1.1
|
||||||
|
[5.1.0]: https://github.com/thephpleague/oauth2-server/compare/5.0.2...5.1.0
|
||||||
|
[5.0.3]: https://github.com/thephpleague/oauth2-server/compare/5.0.3...5.0.2
|
||||||
|
[5.0.2]: https://github.com/thephpleague/oauth2-server/compare/5.0.1...5.0.2
|
||||||
|
[5.0.1]: https://github.com/thephpleague/oauth2-server/compare/5.0.0...5.0.1
|
||||||
|
[5.0.0]: https://github.com/thephpleague/oauth2-server/compare/5.0.0-RC2...5.0.0
|
||||||
|
[5.0.0-RC2]: https://github.com/thephpleague/oauth2-server/compare/5.0.0-RC1...5.0.0-RC2
|
||||||
|
[5.0.0-RC1]: https://github.com/thephpleague/oauth2-server/compare/4.1.5...5.0.0-RC1
|
||||||
|
[4.1.5]: https://github.com/thephpleague/oauth2-server/compare/4.1.4...4.1.5
|
||||||
|
[4.1.4]: https://github.com/thephpleague/oauth2-server/compare/4.1.3...4.1.4
|
||||||
|
[4.1.3]: https://github.com/thephpleague/oauth2-server/compare/4.1.2...4.1.3
|
||||||
|
[4.1.2]: https://github.com/thephpleague/oauth2-server/compare/4.1.1...4.1.2
|
||||||
|
[4.1.1]: https://github.com/thephpleague/oauth2-server/compare/4.0.0...4.1.1
|
||||||
|
[4.1.0]: https://github.com/thephpleague/oauth2-server/compare/4.0.5...4.1.0
|
||||||
|
[4.0.5]: https://github.com/thephpleague/oauth2-server/compare/4.0.4...4.0.5
|
||||||
|
[4.0.4]: https://github.com/thephpleague/oauth2-server/compare/4.0.3...4.0.4
|
||||||
|
[4.0.3]: https://github.com/thephpleague/oauth2-server/compare/4.0.2...4.0.3
|
||||||
|
[4.0.2]: https://github.com/thephpleague/oauth2-server/compare/4.0.1...4.0.2
|
||||||
|
[4.0.1]: https://github.com/thephpleague/oauth2-server/compare/4.0.0...4.0.1
|
||||||
|
[4.0.0]: https://github.com/thephpleague/oauth2-server/compare/3.2.0...4.0.0
|
||||||
|
[3.2.0]: https://github.com/thephpleague/oauth2-server/compare/3.1.2...3.2.0
|
||||||
|
[3.1.2]: https://github.com/thephpleague/oauth2-server/compare/3.1.1...3.1.2
|
||||||
|
[3.1.1]: https://github.com/thephpleague/oauth2-server/compare/3.1.0...3.1.1
|
||||||
|
[3.1.0]: https://github.com/thephpleague/oauth2-server/compare/3.0.1...3.1.0
|
||||||
|
[3.0.1]: https://github.com/thephpleague/oauth2-server/compare/3.0.0...3.0.1
|
||||||
|
[3.0.0]: https://github.com/thephpleague/oauth2-server/compare/2.1.1...3.0.0
|
||||||
|
[2.1.1]: https://github.com/thephpleague/oauth2-server/compare/2.1.0...2.1.1
|
||||||
|
[2.1.0]: https://github.com/thephpleague/oauth2-server/compare/2.0.5...2.1.0
|
||||||
|
[2.0.5]: https://github.com/thephpleague/oauth2-server/compare/2.0.4...2.0.5
|
||||||
|
[2.0.4]: https://github.com/thephpleague/oauth2-server/compare/2.0.3...2.0.4
|
||||||
|
[2.0.3]: https://github.com/thephpleague/oauth2-server/compare/2.0.2...2.0.3
|
||||||
|
[2.0.2]: https://github.com/thephpleague/oauth2-server/compare/2.0.0...2.0.2
|
||||||
|
[2.0.0]: https://github.com/thephpleague/oauth2-server/compare/1.0.8...2.0.0
|
||||||
|
[1.0.8]: https://github.com/thephpleague/oauth2-server/compare/1.0.7...1.0.8
|
||||||
|
[1.0.7]: https://github.com/thephpleague/oauth2-server/compare/1.0.6...1.0.7
|
||||||
|
[1.0.6]: https://github.com/thephpleague/oauth2-server/compare/1.0.5...1.0.6
|
||||||
|
[1.0.5]: https://github.com/thephpleague/oauth2-server/compare/1.0.3...1.0.5
|
||||||
|
[1.0.3]: https://github.com/thephpleague/oauth2-server/compare/1.0.2...1.0.3
|
||||||
|
[1.0.2]: https://github.com/thephpleague/oauth2-server/compare/1.0.1...1.0.2
|
||||||
|
[1.0.1]: https://github.com/thephpleague/oauth2-server/compare/1.0.0...1.0.1
|
||||||
|
73
CODE_OF_CONDUCT.md
Normal file
73
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
|
education, socio-economic status, nationality, personal appearance, race,
|
||||||
|
religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at andrew@noexceptions.io. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
22
CONDUCT.md
22
CONDUCT.md
@ -1,22 +0,0 @@
|
|||||||
# Contributor Code of Conduct
|
|
||||||
|
|
||||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
|
||||||
|
|
||||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery
|
|
||||||
* Personal attacks
|
|
||||||
* Trolling or insulting/derogatory comments
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
|
||||||
* Other unethical or unprofessional conduct.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
|
||||||
|
|
||||||
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations.
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
|
@ -1,7 +1,7 @@
|
|||||||
Thanks for contributing to this project.
|
Thanks for contributing to this project.
|
||||||
|
|
||||||
|
|
||||||
**Please submit your pull request against the `develop` branch only.**
|
**Please submit your pull request against the `master` branch only.**
|
||||||
|
|
||||||
|
|
||||||
Please ensure that you run `phpunit` from the project root after you've made any changes.
|
Please ensure that you run `phpunit` from the project root after you've made any changes.
|
||||||
|
48
README.md
48
README.md
@ -6,10 +6,11 @@
|
|||||||
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure)
|
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure)
|
||||||
[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server)
|
[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server)
|
||||||
[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server)
|
[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server)
|
||||||
|
[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat-square)](https://github.com/phpstan/phpstan)
|
||||||
|
|
||||||
`league/oauth2-server` is a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
`league/oauth2-server` is a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
||||||
|
|
||||||
It supports out of the box the following grants:
|
Out of the box it supports the following grants:
|
||||||
|
|
||||||
* Authorization code grant
|
* Authorization code grant
|
||||||
* Implicit grant
|
* Implicit grant
|
||||||
@ -30,26 +31,51 @@ This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](ht
|
|||||||
|
|
||||||
The following versions of PHP are supported:
|
The following versions of PHP are supported:
|
||||||
|
|
||||||
* PHP 5.5 (>=5.5.9)
|
|
||||||
* PHP 5.6
|
|
||||||
* PHP 7.0
|
* PHP 7.0
|
||||||
* PHP 7.1
|
* PHP 7.1
|
||||||
* HHVM
|
* PHP 7.2
|
||||||
|
|
||||||
The `openssl` extension is also required.
|
The `openssl` extension is 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 between other packages and frameworks.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
composer require league/oauth2-server
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The library documentation can be found at [https://oauth2.thephpleague.com](https://oauth2.thephpleague.com).
|
The library documentation can be found at [https://oauth2.thephpleague.com](https://oauth2.thephpleague.com).
|
||||||
You can contribute to the documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/).
|
You can contribute to the documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/).
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
The library uses [PHPUnit](https://phpunit.de/) for unit tests and [PHPStan](https://github.com/phpstan/phpstan) for static analysis of the code.
|
||||||
|
|
||||||
|
```
|
||||||
|
vendor/bin/phpunit
|
||||||
|
vendor/bin/phpstan analyse -l 7 -c phpstan.neon src tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Continous Integration
|
||||||
|
|
||||||
|
We use [Travis CI](https://travis-ci.org/), [Scrutinizer](https://scrutinizer-ci.com/), and [StyleCI](https://styleci.io/) for continuous integration. Check out [our](https://github.com/thephpleague/oauth2-server/blob/master/.travis.yml) [configuration](https://github.com/thephpleague/oauth2-server/blob/master/.scrutinizer.yml) [files](https://github.com/thephpleague/oauth2-server/blob/master/.styleci.yml) if you'd like to know more.
|
||||||
|
|
||||||
|
## Community Integrations
|
||||||
|
|
||||||
|
* [Drupal](https://www.drupal.org/project/simple_oauth)
|
||||||
|
* [Laravel Passport](https://github.com/laravel/passport)
|
||||||
|
* [OAuth 2 Server for CakePHP 3](https://github.com/uafrica/oauth-server)
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
[See the project releases page](https://github.com/thephpleague/oauth2-server/releases)
|
See the [project changelog](https://github.com/thephpleague/oauth2-server/blob/master/CHANGELOG.md)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details.
|
Contributions are always welcome. Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CODE_OF_CONDUCT.md) for details.
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
@ -71,8 +97,14 @@ This package is released under the MIT License. See the bundled [LICENSE](https:
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie).
|
This code is principally developed and maintained by [Andy Millington](https://twitter.com/Sephster) and [Simon Hamp](https://twitter.com/simonhamp).
|
||||||
|
|
||||||
Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors)
|
Between 2012 and 2017 this library was developed and maintained by [Alex Bilbie](https://alexbilbie.com/).
|
||||||
|
|
||||||
|
PHP OAuth 2.0 Server is one of many packages provided by The PHP League. To find out more, please visit [our website](https://thephpleague.com).
|
||||||
|
|
||||||
|
Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors).
|
||||||
|
|
||||||
|
Additional thanks go to the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source) for funding a security audit of this library.
|
||||||
|
|
||||||
The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme.
|
The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme.
|
||||||
|
@ -4,17 +4,19 @@
|
|||||||
"homepage": "https://oauth2.thephpleague.com/",
|
"homepage": "https://oauth2.thephpleague.com/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5.9",
|
"php": ">=7.0.0",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"league/event": "^2.1",
|
"league/event": "^2.1",
|
||||||
"lcobucci/jwt": "^3.1",
|
"lcobucci/jwt": "^3.2.2",
|
||||||
"paragonie/random_compat": "^1.1 || ^2.0",
|
"psr/http-message": "^1.0.1",
|
||||||
"psr/http-message": "^1.0"
|
"defuse/php-encryption": "^2.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^4.8 || ^5.0",
|
"phpunit/phpunit": "^6.3 || ^7.0",
|
||||||
"zendframework/zend-diactoros": "^1.0",
|
"zendframework/zend-diactoros": "^1.3.2",
|
||||||
"indigophp/hash-compat": "^1.1"
|
"phpstan/phpstan": "^0.9.2",
|
||||||
|
"phpstan/phpstan-phpunit": "^0.9.4",
|
||||||
|
"phpstan/phpstan-strict-rules": "^0.9.0"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
@ -59,13 +61,5 @@
|
|||||||
"psr-4": {
|
"psr-4": {
|
||||||
"LeagueTests\\": "tests/"
|
"LeagueTests\\": "tests/"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-V5-WIP": "5.0-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"indigophp/hash-compat": "Polyfill for hash_equals function for PHP 5.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"league/event": "^2.1",
|
"league/event": "^2.1",
|
||||||
"lcobucci/jwt": "^3.1",
|
"lcobucci/jwt": "^3.1",
|
||||||
"paragonie/random_compat": "^1.1",
|
"paragonie/random_compat": "^2.0",
|
||||||
"psr/http-message": "^1.0"
|
"psr/http-message": "^1.0",
|
||||||
|
"defuse/php-encryption": "^2.1",
|
||||||
|
"zendframework/zend-diactoros": "^1.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
178
examples/composer.lock
generated
178
examples/composer.lock
generated
@ -4,23 +4,25 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "48bcb7a3514d7c7f271c554ba1440124",
|
"content-hash": "9813ed7c3b6dcf107f44df9392935b8f",
|
||||||
"content-hash": "e41be75973527cb9d63f27ad14ac8624",
|
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "container-interop/container-interop",
|
"name": "container-interop/container-interop",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/container-interop/container-interop.git",
|
"url": "https://github.com/container-interop/container-interop.git",
|
||||||
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
|
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
|
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8",
|
||||||
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
|
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
|
"require": {
|
||||||
|
"psr/container": "^1.0"
|
||||||
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@ -32,7 +34,8 @@
|
|||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
||||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||||
"time": "2014-12-30 15:22:37"
|
"homepage": "https://github.com/container-interop/container-interop",
|
||||||
|
"time": "2017-02-14T19:40:03+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/fast-route",
|
"name": "nikic/fast-route",
|
||||||
@ -75,7 +78,7 @@
|
|||||||
"router",
|
"router",
|
||||||
"routing"
|
"routing"
|
||||||
],
|
],
|
||||||
"time": "2015-06-18 19:15:47"
|
"time": "2015-06-18T19:15:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pimple/pimple",
|
"name": "pimple/pimple",
|
||||||
@ -121,20 +124,69 @@
|
|||||||
"container",
|
"container",
|
||||||
"dependency injection"
|
"dependency injection"
|
||||||
],
|
],
|
||||||
"time": "2015-09-11 15:10:35"
|
"time": "2015-09-11T15:10:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/container",
|
||||||
"version": "1.0",
|
"version": "1.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/http-message.git",
|
"url": "https://github.com/php-fig/container.git",
|
||||||
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
|
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||||
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Container\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "http://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||||
|
"homepage": "https://github.com/php-fig/container",
|
||||||
|
"keywords": [
|
||||||
|
"PSR-11",
|
||||||
|
"container",
|
||||||
|
"container-interface",
|
||||||
|
"container-interop",
|
||||||
|
"psr"
|
||||||
|
],
|
||||||
|
"time": "2017-02-14T16:28:37+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/http-message",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/http-message.git",
|
||||||
|
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||||
|
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -162,6 +214,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interface for HTTP messages",
|
"description": "Common interface for HTTP messages",
|
||||||
|
"homepage": "https://github.com/php-fig/http-message",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"http",
|
"http",
|
||||||
"http-message",
|
"http-message",
|
||||||
@ -170,7 +223,7 @@
|
|||||||
"request",
|
"request",
|
||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
"time": "2015-05-04 20:22:00"
|
"time": "2016-08-06T14:39:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "slim/slim",
|
"name": "slim/slim",
|
||||||
@ -236,22 +289,85 @@
|
|||||||
"micro",
|
"micro",
|
||||||
"router"
|
"router"
|
||||||
],
|
],
|
||||||
"time": "2015-12-07 14:11:09"
|
"time": "2015-12-07T14:11:09+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "lcobucci/jwt",
|
"name": "defuse/php-encryption",
|
||||||
"version": "3.1.1",
|
"version": "v2.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/lcobucci/jwt.git",
|
"url": "https://github.com/defuse/php-encryption.git",
|
||||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5"
|
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5",
|
"url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
|
||||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5",
|
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"paragonie/random_compat": "~2.0",
|
||||||
|
"php": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"nikic/php-parser": "^2.0|^3.0",
|
||||||
|
"phpunit/phpunit": "^4|^5"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/generate-defuse-key"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Defuse\\Crypto\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Hornby",
|
||||||
|
"email": "taylor@defuse.ca",
|
||||||
|
"homepage": "https://defuse.ca/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Scott Arciszewski",
|
||||||
|
"email": "info@paragonie.com",
|
||||||
|
"homepage": "https://paragonie.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Secure PHP Encryption Library",
|
||||||
|
"keywords": [
|
||||||
|
"aes",
|
||||||
|
"authenticated encryption",
|
||||||
|
"cipher",
|
||||||
|
"crypto",
|
||||||
|
"cryptography",
|
||||||
|
"encrypt",
|
||||||
|
"encryption",
|
||||||
|
"openssl",
|
||||||
|
"security",
|
||||||
|
"symmetric key cryptography"
|
||||||
|
],
|
||||||
|
"time": "2017-05-18T21:28:48+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lcobucci/jwt",
|
||||||
|
"version": "3.2.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/lcobucci/jwt.git",
|
||||||
|
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/ddce703826f9c5229781933b1a39069e38e6a0f3",
|
||||||
|
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -259,7 +375,7 @@
|
|||||||
"php": ">=5.5"
|
"php": ">=5.5"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mdanter/ecc": "~0.3",
|
"mdanter/ecc": "~0.3.1",
|
||||||
"mikey179/vfsstream": "~1.5",
|
"mikey179/vfsstream": "~1.5",
|
||||||
"phpmd/phpmd": "~2.2",
|
"phpmd/phpmd": "~2.2",
|
||||||
"phpunit/php-invoker": "~1.1",
|
"phpunit/php-invoker": "~1.1",
|
||||||
@ -296,7 +412,7 @@
|
|||||||
"JWS",
|
"JWS",
|
||||||
"jwt"
|
"jwt"
|
||||||
],
|
],
|
||||||
"time": "2016-03-24 22:46:13"
|
"time": "2016-10-31T20:09:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/event",
|
"name": "league/event",
|
||||||
@ -346,20 +462,20 @@
|
|||||||
"event",
|
"event",
|
||||||
"listener"
|
"listener"
|
||||||
],
|
],
|
||||||
"time": "2015-05-21 12:24:47"
|
"time": "2015-05-21T12:24:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "paragonie/random_compat",
|
"name": "paragonie/random_compat",
|
||||||
"version": "v1.4.1",
|
"version": "v2.0.10",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/paragonie/random_compat.git",
|
"url": "https://github.com/paragonie/random_compat.git",
|
||||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
|
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
|
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
|
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -394,7 +510,7 @@
|
|||||||
"pseudorandom",
|
"pseudorandom",
|
||||||
"random"
|
"random"
|
||||||
],
|
],
|
||||||
"time": "2016-03-18 20:34:03"
|
"time": "2017-03-13T16:27:32+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
@ -49,16 +49,18 @@ $app->get(
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$totalUsers = count($users);
|
||||||
|
|
||||||
// If the access token doesn't have the `basic` scope hide users' names
|
// If the access token doesn't have the `basic` scope hide users' names
|
||||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < $totalUsers; $i++) {
|
||||||
unset($users[$i]['name']);
|
unset($users[$i]['name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the access token doesn't have the `email` scope hide users' email addresses
|
// If the access token doesn't have the `email` scope hide users' email addresses
|
||||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||||
for ($i = 0; $i < count($users); $i++) {
|
for ($i = 0; $i < $totalUsers; $i++) {
|
||||||
unset($users[$i]['email']);
|
unset($users[$i]['email']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ $app = new App([
|
|||||||
$refreshTokenRepository = new RefreshTokenRepository();
|
$refreshTokenRepository = new RefreshTokenRepository();
|
||||||
|
|
||||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -44,7 +43,7 @@ $app = new App([
|
|||||||
$accessTokenRepository,
|
$accessTokenRepository,
|
||||||
$scopeRepository,
|
$scopeRepository,
|
||||||
$privateKeyPath,
|
$privateKeyPath,
|
||||||
$publicKeyPath
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||||
|
@ -32,7 +32,6 @@ $app = new App([
|
|||||||
// Path to public and private keys
|
// Path to public and private keys
|
||||||
$privateKey = 'file://' . __DIR__ . '/../private.key';
|
$privateKey = 'file://' . __DIR__ . '/../private.key';
|
||||||
//$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase
|
//$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase
|
||||||
$publicKey = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -40,7 +39,7 @@ $app = new App([
|
|||||||
$accessTokenRepository,
|
$accessTokenRepository,
|
||||||
$scopeRepository,
|
$scopeRepository,
|
||||||
$privateKey,
|
$privateKey,
|
||||||
$publicKey
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enable the client credentials grant on the server
|
// Enable the client credentials grant on the server
|
||||||
|
@ -32,7 +32,6 @@ $app = new App([
|
|||||||
$accessTokenRepository = new AccessTokenRepository();
|
$accessTokenRepository = new AccessTokenRepository();
|
||||||
|
|
||||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -40,7 +39,7 @@ $app = new App([
|
|||||||
$accessTokenRepository,
|
$accessTokenRepository,
|
||||||
$scopeRepository,
|
$scopeRepository,
|
||||||
$privateKeyPath,
|
$privateKeyPath,
|
||||||
$publicKeyPath
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enable the implicit grant on the server with a token TTL of 1 hour
|
// Enable the implicit grant on the server with a token TTL of 1 hour
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use League\OAuth2\Server\AuthorizationServer;
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
use League\OAuth2\Server\ResourceServer;
|
|
||||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||||
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
||||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||||
|
use League\OAuth2\Server\ResourceServer;
|
||||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||||
@ -38,7 +38,6 @@ $app = new App([
|
|||||||
$refreshTokenRepository = new RefreshTokenRepository();
|
$refreshTokenRepository = new RefreshTokenRepository();
|
||||||
|
|
||||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -46,7 +45,7 @@ $app = new App([
|
|||||||
$accessTokenRepository,
|
$accessTokenRepository,
|
||||||
$scopeRepository,
|
$scopeRepository,
|
||||||
$privateKeyPath,
|
$privateKeyPath,
|
||||||
$publicKeyPath
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||||
@ -62,7 +61,7 @@ $app = new App([
|
|||||||
// Enable the refresh token grant on the server with a token TTL of 1 month
|
// Enable the refresh token grant on the server with a token TTL of 1 month
|
||||||
$server->enableGrantType(
|
$server->enableGrantType(
|
||||||
new RefreshTokenGrant($refreshTokenRepository),
|
new RefreshTokenGrant($refreshTokenRepository),
|
||||||
new \DateInterval('PT1M')
|
new \DateInterval('P1M')
|
||||||
);
|
);
|
||||||
|
|
||||||
return $server;
|
return $server;
|
||||||
@ -74,6 +73,7 @@ $app = new App([
|
|||||||
new AccessTokenRepository(),
|
new AccessTokenRepository(),
|
||||||
$publicKeyPath
|
$publicKeyPath
|
||||||
);
|
);
|
||||||
|
|
||||||
return $server;
|
return $server;
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -24,7 +24,7 @@ $app = new App([
|
|||||||
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
||||||
new ScopeRepository(), // instance of ScopeRepositoryInterface
|
new ScopeRepository(), // instance of ScopeRepositoryInterface
|
||||||
'file://' . __DIR__ . '/../private.key', // path to private key
|
'file://' . __DIR__ . '/../private.key', // path to private key
|
||||||
'file://' . __DIR__ . '/../public.key' // path to public key
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' // encryption key
|
||||||
);
|
);
|
||||||
|
|
||||||
$grant = new PasswordGrant(
|
$grant = new PasswordGrant(
|
||||||
|
@ -17,7 +17,6 @@ use OAuth2ServerExamples\Repositories\ScopeRepository;
|
|||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Slim\App;
|
use Slim\App;
|
||||||
use Zend\Diactoros\Stream;
|
|
||||||
|
|
||||||
include __DIR__ . '/../vendor/autoload.php';
|
include __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
@ -33,7 +32,6 @@ $app = new App([
|
|||||||
$refreshTokenRepository = new RefreshTokenRepository();
|
$refreshTokenRepository = new RefreshTokenRepository();
|
||||||
|
|
||||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
|
||||||
|
|
||||||
// Setup the authorization server
|
// Setup the authorization server
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -41,7 +39,7 @@ $app = new App([
|
|||||||
$accessTokenRepository,
|
$accessTokenRepository,
|
||||||
$scopeRepository,
|
$scopeRepository,
|
||||||
$privateKeyPath,
|
$privateKeyPath,
|
||||||
$publicKeyPath
|
'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enable the refresh token grant on the server
|
// Enable the refresh token grant on the server
|
||||||
@ -66,10 +64,9 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI
|
|||||||
} catch (OAuthServerException $exception) {
|
} catch (OAuthServerException $exception) {
|
||||||
return $exception->generateHttpResponse($response);
|
return $exception->generateHttpResponse($response);
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
$body = new Stream('php://temp', 'r+');
|
$response->getBody()->write($exception->getMessage());
|
||||||
$body->write($exception->getMessage());
|
|
||||||
|
|
||||||
return $response->withStatus(500)->withBody($body);
|
return $response->withStatus(500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class ClientRepository implements ClientRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true)
|
public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true)
|
||||||
{
|
{
|
||||||
$clients = [
|
$clients = [
|
||||||
'myawesomeapp' => [
|
'myawesomeapp' => [
|
||||||
|
10
phpstan.neon
Normal file
10
phpstan.neon
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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
|
||||||
|
tags:
|
||||||
|
- phpstan.broker.dynamicMethodReturnTypeExtension
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server;
|
namespace League\OAuth2\Server;
|
||||||
|
|
||||||
|
use Defuse\Crypto\Key;
|
||||||
use League\Event\EmitterAwareInterface;
|
use League\Event\EmitterAwareInterface;
|
||||||
use League\Event\EmitterAwareTrait;
|
use League\Event\EmitterAwareTrait;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
@ -17,6 +18,7 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
|||||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||||
|
use League\OAuth2\Server\ResponseTypes\AbstractResponseType;
|
||||||
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
||||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
@ -66,6 +68,16 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
*/
|
*/
|
||||||
private $scopeRepository;
|
private $scopeRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|Key
|
||||||
|
*/
|
||||||
|
private $encryptionKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $defaultScope = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New server instance.
|
* New server instance.
|
||||||
*
|
*
|
||||||
@ -73,7 +85,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||||
* @param ScopeRepositoryInterface $scopeRepository
|
* @param ScopeRepositoryInterface $scopeRepository
|
||||||
* @param CryptKey|string $privateKey
|
* @param CryptKey|string $privateKey
|
||||||
* @param CryptKey|string $publicKey
|
* @param string|Key $encryptionKey
|
||||||
* @param null|ResponseTypeInterface $responseType
|
* @param null|ResponseTypeInterface $responseType
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -81,7 +93,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||||
ScopeRepositoryInterface $scopeRepository,
|
ScopeRepositoryInterface $scopeRepository,
|
||||||
$privateKey,
|
$privateKey,
|
||||||
$publicKey,
|
$encryptionKey,
|
||||||
ResponseTypeInterface $responseType = null
|
ResponseTypeInterface $responseType = null
|
||||||
) {
|
) {
|
||||||
$this->clientRepository = $clientRepository;
|
$this->clientRepository = $clientRepository;
|
||||||
@ -92,12 +104,7 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
$privateKey = new CryptKey($privateKey);
|
$privateKey = new CryptKey($privateKey);
|
||||||
}
|
}
|
||||||
$this->privateKey = $privateKey;
|
$this->privateKey = $privateKey;
|
||||||
|
$this->encryptionKey = $encryptionKey;
|
||||||
if ($publicKey instanceof CryptKey === false) {
|
|
||||||
$publicKey = new CryptKey($publicKey);
|
|
||||||
}
|
|
||||||
$this->publicKey = $publicKey;
|
|
||||||
|
|
||||||
$this->responseType = $responseType;
|
$this->responseType = $responseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,9 +123,10 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
$grantType->setAccessTokenRepository($this->accessTokenRepository);
|
$grantType->setAccessTokenRepository($this->accessTokenRepository);
|
||||||
$grantType->setClientRepository($this->clientRepository);
|
$grantType->setClientRepository($this->clientRepository);
|
||||||
$grantType->setScopeRepository($this->scopeRepository);
|
$grantType->setScopeRepository($this->scopeRepository);
|
||||||
|
$grantType->setDefaultScope($this->defaultScope);
|
||||||
$grantType->setPrivateKey($this->privateKey);
|
$grantType->setPrivateKey($this->privateKey);
|
||||||
$grantType->setPublicKey($this->publicKey);
|
|
||||||
$grantType->setEmitter($this->getEmitter());
|
$grantType->setEmitter($this->getEmitter());
|
||||||
|
$grantType->setEncryptionKey($this->encryptionKey);
|
||||||
|
|
||||||
$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
|
$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
|
||||||
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
|
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
|
||||||
@ -172,7 +180,9 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
|
public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
|
||||||
{
|
{
|
||||||
foreach ($this->enabledGrantTypes as $grantType) {
|
foreach ($this->enabledGrantTypes as $grantType) {
|
||||||
if ($grantType->canRespondToAccessTokenRequest($request)) {
|
if (!$grantType->canRespondToAccessTokenRequest($request)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$tokenResponse = $grantType->respondToAccessTokenRequest(
|
$tokenResponse = $grantType->respondToAccessTokenRequest(
|
||||||
$request,
|
$request,
|
||||||
$this->getResponseType(),
|
$this->getResponseType(),
|
||||||
@ -183,7 +193,6 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
return $tokenResponse->generateHttpResponse($response);
|
return $tokenResponse->generateHttpResponse($response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
throw OAuthServerException::unsupportedGrantType();
|
throw OAuthServerException::unsupportedGrantType();
|
||||||
}
|
}
|
||||||
@ -199,8 +208,21 @@ class AuthorizationServer implements EmitterAwareInterface
|
|||||||
$this->responseType = new BearerTokenResponse();
|
$this->responseType = new BearerTokenResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->responseType instanceof AbstractResponseType === true) {
|
||||||
$this->responseType->setPrivateKey($this->privateKey);
|
$this->responseType->setPrivateKey($this->privateKey);
|
||||||
|
}
|
||||||
|
$this->responseType->setEncryptionKey($this->encryptionKey);
|
||||||
|
|
||||||
return $this->responseType;
|
return $this->responseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default scope for the authorization server.
|
||||||
|
*
|
||||||
|
* @param string $defaultScope
|
||||||
|
*/
|
||||||
|
public function setDefaultScope($defaultScope)
|
||||||
|
{
|
||||||
|
$this->defaultScope = $defaultScope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ namespace League\OAuth2\Server\AuthorizationValidators;
|
|||||||
use Lcobucci\JWT\Parser;
|
use Lcobucci\JWT\Parser;
|
||||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||||
use Lcobucci\JWT\ValidationData;
|
use Lcobucci\JWT\ValidationData;
|
||||||
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\CryptTrait;
|
use League\OAuth2\Server\CryptTrait;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
@ -26,6 +27,11 @@ class BearerTokenValidator implements AuthorizationValidatorInterface
|
|||||||
*/
|
*/
|
||||||
private $accessTokenRepository;
|
private $accessTokenRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \League\OAuth2\Server\CryptKey
|
||||||
|
*/
|
||||||
|
protected $publicKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||||
*/
|
*/
|
||||||
@ -34,6 +40,16 @@ class BearerTokenValidator implements AuthorizationValidatorInterface
|
|||||||
$this->accessTokenRepository = $accessTokenRepository;
|
$this->accessTokenRepository = $accessTokenRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the public key
|
||||||
|
*
|
||||||
|
* @param \League\OAuth2\Server\CryptKey $key
|
||||||
|
*/
|
||||||
|
public function setPublicKey(CryptKey $key)
|
||||||
|
{
|
||||||
|
$this->publicKey = $key;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -49,9 +65,13 @@ class BearerTokenValidator implements AuthorizationValidatorInterface
|
|||||||
try {
|
try {
|
||||||
// Attempt to parse and validate the JWT
|
// Attempt to parse and validate the JWT
|
||||||
$token = (new Parser())->parse($jwt);
|
$token = (new Parser())->parse($jwt);
|
||||||
|
try {
|
||||||
if ($token->verify(new Sha256(), $this->publicKey->getKeyPath()) === false) {
|
if ($token->verify(new Sha256(), $this->publicKey->getKeyPath()) === false) {
|
||||||
throw OAuthServerException::accessDenied('Access token could not be verified');
|
throw OAuthServerException::accessDenied('Access token could not be verified');
|
||||||
}
|
}
|
||||||
|
} catch (\BadMethodCallException $exception) {
|
||||||
|
throw OAuthServerException::accessDenied('Access token is not signed');
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure access token hasn't expired
|
// Ensure access token hasn't expired
|
||||||
$data = new ValidationData();
|
$data = new ValidationData();
|
||||||
|
@ -14,7 +14,7 @@ namespace League\OAuth2\Server;
|
|||||||
class CryptKey
|
class CryptKey
|
||||||
{
|
{
|
||||||
const RSA_KEY_PATTERN =
|
const RSA_KEY_PATTERN =
|
||||||
'/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----\n)(.|\n)+(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)$/';
|
'/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----)\R.*(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)\R?$/s';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
@ -29,8 +29,9 @@ class CryptKey
|
|||||||
/**
|
/**
|
||||||
* @param string $keyPath
|
* @param string $keyPath
|
||||||
* @param null|string $passPhrase
|
* @param null|string $passPhrase
|
||||||
|
* @param bool $keyPermissionsCheck
|
||||||
*/
|
*/
|
||||||
public function __construct($keyPath, $passPhrase = null)
|
public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true)
|
||||||
{
|
{
|
||||||
if (preg_match(self::RSA_KEY_PATTERN, $keyPath)) {
|
if (preg_match(self::RSA_KEY_PATTERN, $keyPath)) {
|
||||||
$keyPath = $this->saveKeyToFile($keyPath);
|
$keyPath = $this->saveKeyToFile($keyPath);
|
||||||
@ -44,6 +45,18 @@ class CryptKey
|
|||||||
throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath));
|
throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($keyPermissionsCheck === true) {
|
||||||
|
// Verify the permissions of the key
|
||||||
|
$keyPathPerms = decoct(fileperms($keyPath) & 0777);
|
||||||
|
if (in_array($keyPathPerms, ['400', '440', '600', '660'], true) === false) {
|
||||||
|
trigger_error(sprintf(
|
||||||
|
'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
|
||||||
|
$keyPath,
|
||||||
|
$keyPathPerms
|
||||||
|
), E_USER_NOTICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->keyPath = $keyPath;
|
$this->keyPath = $keyPath;
|
||||||
$this->passPhrase = $passPhrase;
|
$this->passPhrase = $passPhrase;
|
||||||
}
|
}
|
||||||
@ -57,15 +70,30 @@ class CryptKey
|
|||||||
*/
|
*/
|
||||||
private function saveKeyToFile($key)
|
private function saveKeyToFile($key)
|
||||||
{
|
{
|
||||||
$keyPath = sys_get_temp_dir() . '/' . sha1($key) . '.key';
|
$tmpDir = sys_get_temp_dir();
|
||||||
|
$keyPath = $tmpDir . '/' . sha1($key) . '.key';
|
||||||
|
|
||||||
if (!file_exists($keyPath) && !touch($keyPath)) {
|
if (file_exists($keyPath)) {
|
||||||
|
return 'file://' . $keyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!touch($keyPath)) {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
throw new \RuntimeException('"%s" key file could not be created', $keyPath);
|
throw new \RuntimeException(sprintf('"%s" key file could not be created', $keyPath));
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
file_put_contents($keyPath, $key);
|
if (file_put_contents($keyPath, $key) === false) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new \RuntimeException(sprintf('Unable to write key file to temporary directory "%s"', $tmpDir));
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chmod($keyPath, 0600) === false) {
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
throw new \RuntimeException(sprintf('The key file "%s" file mode could not be changed with chmod to 600', $keyPath));
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
|
||||||
return 'file://' . $keyPath;
|
return 'file://' . $keyPath;
|
||||||
}
|
}
|
||||||
|
@ -11,37 +11,15 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server;
|
namespace League\OAuth2\Server;
|
||||||
|
|
||||||
|
use Defuse\Crypto\Crypto;
|
||||||
|
use Defuse\Crypto\Key;
|
||||||
|
|
||||||
trait CryptTrait
|
trait CryptTrait
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var CryptKey
|
* @var string|Key
|
||||||
*/
|
*/
|
||||||
protected $privateKey;
|
protected $encryptionKey;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var CryptKey
|
|
||||||
*/
|
|
||||||
protected $publicKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set path to private key.
|
|
||||||
*
|
|
||||||
* @param CryptKey $privateKey
|
|
||||||
*/
|
|
||||||
public function setPrivateKey(CryptKey $privateKey)
|
|
||||||
{
|
|
||||||
$this->privateKey = $privateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set path to public key.
|
|
||||||
*
|
|
||||||
* @param CryptKey $publicKey
|
|
||||||
*/
|
|
||||||
public function setPublicKey(CryptKey $publicKey)
|
|
||||||
{
|
|
||||||
$this->publicKey = $publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt data with a private key.
|
* Encrypt data with a private key.
|
||||||
@ -54,30 +32,15 @@ trait CryptTrait
|
|||||||
*/
|
*/
|
||||||
protected function encrypt($unencryptedData)
|
protected function encrypt($unencryptedData)
|
||||||
{
|
{
|
||||||
$privateKey = openssl_pkey_get_private($this->privateKey->getKeyPath(), $this->privateKey->getPassPhrase());
|
try {
|
||||||
$privateKeyDetails = @openssl_pkey_get_details($privateKey);
|
if ($this->encryptionKey instanceof Key) {
|
||||||
if ($privateKeyDetails === null) {
|
return Crypto::encrypt($unencryptedData, $this->encryptionKey);
|
||||||
throw new \LogicException(
|
|
||||||
sprintf('Could not get details of private key: %s', $this->privateKey->getKeyPath())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11;
|
return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
|
||||||
$output = '';
|
} catch (\Exception $e) {
|
||||||
|
throw new \LogicException($e->getMessage());
|
||||||
while ($unencryptedData) {
|
|
||||||
$chunk = substr($unencryptedData, 0, $chunkSize);
|
|
||||||
$unencryptedData = substr($unencryptedData, $chunkSize);
|
|
||||||
if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new \LogicException('Failed to encrypt data');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
}
|
||||||
$output .= $encrypted;
|
|
||||||
}
|
|
||||||
openssl_pkey_free($privateKey);
|
|
||||||
|
|
||||||
return base64_encode($output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,31 +54,24 @@ trait CryptTrait
|
|||||||
*/
|
*/
|
||||||
protected function decrypt($encryptedData)
|
protected function decrypt($encryptedData)
|
||||||
{
|
{
|
||||||
$publicKey = openssl_pkey_get_public($this->publicKey->getKeyPath());
|
try {
|
||||||
$publicKeyDetails = @openssl_pkey_get_details($publicKey);
|
if ($this->encryptionKey instanceof Key) {
|
||||||
if ($publicKeyDetails === null) {
|
return Crypto::decrypt($encryptedData, $this->encryptionKey);
|
||||||
throw new \LogicException(
|
|
||||||
sprintf('Could not get details of public key: %s', $this->publicKey->getKeyPath())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$chunkSize = ceil($publicKeyDetails['bits'] / 8);
|
return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
|
||||||
$output = '';
|
} catch (\Exception $e) {
|
||||||
|
throw new \LogicException($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$encryptedData = base64_decode($encryptedData);
|
/**
|
||||||
|
* Set the encryption key
|
||||||
while ($encryptedData) {
|
*
|
||||||
$chunk = substr($encryptedData, 0, $chunkSize);
|
* @param string|Key $key
|
||||||
$encryptedData = substr($encryptedData, $chunkSize);
|
*/
|
||||||
if (openssl_public_decrypt($chunk, $decrypted, $publicKey/*, OPENSSL_PKCS1_OAEP_PADDING*/) === false) {
|
public function setEncryptionKey($key = null)
|
||||||
// @codeCoverageIgnoreStart
|
{
|
||||||
throw new \LogicException('Failed to decrypt data');
|
$this->encryptionKey = $key;
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
$output .= $decrypted;
|
|
||||||
}
|
|
||||||
openssl_pkey_free($publicKey);
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Entities;
|
namespace League\OAuth2\Server\Entities;
|
||||||
|
|
||||||
|
use Lcobucci\JWT\Token;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
|
||||||
interface AccessTokenEntityInterface extends TokenInterface
|
interface AccessTokenEntityInterface extends TokenInterface
|
||||||
@ -18,7 +19,7 @@ interface AccessTokenEntityInterface extends TokenInterface
|
|||||||
*
|
*
|
||||||
* @param CryptKey $privateKey
|
* @param CryptKey $privateKey
|
||||||
*
|
*
|
||||||
* @return string
|
* @return Token
|
||||||
*/
|
*/
|
||||||
public function convertToJWT(CryptKey $privateKey);
|
public function convertToJWT(CryptKey $privateKey);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace League\OAuth2\Server\Entities;
|
|||||||
interface AuthCodeEntityInterface extends TokenInterface
|
interface AuthCodeEntityInterface extends TokenInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getRedirectUri();
|
public function getRedirectUri();
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ interface RefreshTokenEntityInterface
|
|||||||
/**
|
/**
|
||||||
* Set the token's identifier.
|
* Set the token's identifier.
|
||||||
*
|
*
|
||||||
* @param $identifier
|
* @param mixed $identifier
|
||||||
*/
|
*/
|
||||||
public function setIdentifier($identifier);
|
public function setIdentifier($identifier);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ interface TokenInterface
|
|||||||
/**
|
/**
|
||||||
* Set the token's identifier.
|
* Set the token's identifier.
|
||||||
*
|
*
|
||||||
* @param $identifier
|
* @param mixed $identifier
|
||||||
*/
|
*/
|
||||||
public function setIdentifier($identifier);
|
public function setIdentifier($identifier);
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ interface TokenInterface
|
|||||||
/**
|
/**
|
||||||
* Set the identifier of the user associated with the token.
|
* Set the identifier of the user associated with the token.
|
||||||
*
|
*
|
||||||
* @param string|int $identifier The identifier of the user
|
* @param string|int|null $identifier The identifier of the user
|
||||||
*/
|
*/
|
||||||
public function setUserIdentifier($identifier);
|
public function setUserIdentifier($identifier);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the token user's identifier.
|
* Get the token user's identifier.
|
||||||
*
|
*
|
||||||
* @return string|int
|
* @return string|int|null
|
||||||
*/
|
*/
|
||||||
public function getUserIdentifier();
|
public function getUserIdentifier();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Entities\Traits;
|
|||||||
use Lcobucci\JWT\Builder;
|
use Lcobucci\JWT\Builder;
|
||||||
use Lcobucci\JWT\Signer\Key;
|
use Lcobucci\JWT\Signer\Key;
|
||||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||||
|
use Lcobucci\JWT\Token;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
@ -23,7 +24,7 @@ trait AccessTokenTrait
|
|||||||
*
|
*
|
||||||
* @param CryptKey $privateKey
|
* @param CryptKey $privateKey
|
||||||
*
|
*
|
||||||
* @return string
|
* @return Token
|
||||||
*/
|
*/
|
||||||
public function convertToJWT(CryptKey $privateKey)
|
public function convertToJWT(CryptKey $privateKey)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ trait AuthCodeTrait
|
|||||||
protected $redirectUri;
|
protected $redirectUri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getRedirectUri()
|
public function getRedirectUri()
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ namespace League\OAuth2\Server\Entities\Traits;
|
|||||||
|
|
||||||
trait EntityTrait
|
trait EntityTrait
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $identifier;
|
protected $identifier;
|
||||||
|
@ -25,7 +25,7 @@ trait TokenEntityTrait
|
|||||||
protected $expiryDateTime;
|
protected $expiryDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|int
|
* @var string|int|null
|
||||||
*/
|
*/
|
||||||
protected $userIdentifier;
|
protected $userIdentifier;
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ trait TokenEntityTrait
|
|||||||
/**
|
/**
|
||||||
* Set the identifier of the user associated with the token.
|
* Set the identifier of the user associated with the token.
|
||||||
*
|
*
|
||||||
* @param string|int $identifier The identifier of the user
|
* @param string|int|null $identifier The identifier of the user
|
||||||
*/
|
*/
|
||||||
public function setUserIdentifier($identifier)
|
public function setUserIdentifier($identifier)
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@ trait TokenEntityTrait
|
|||||||
/**
|
/**
|
||||||
* Get the token user's identifier.
|
* Get the token user's identifier.
|
||||||
*
|
*
|
||||||
* @return string|int
|
* @return string|int|null
|
||||||
*/
|
*/
|
||||||
public function getUserIdentifier()
|
public function getUserIdentifier()
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,11 @@ class OAuthServerException extends \Exception
|
|||||||
*/
|
*/
|
||||||
private $redirectUri;
|
private $redirectUri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $payload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw a new exception.
|
* Throw a new exception.
|
||||||
*
|
*
|
||||||
@ -50,6 +55,33 @@ class OAuthServerException extends \Exception
|
|||||||
$this->errorType = $errorType;
|
$this->errorType = $errorType;
|
||||||
$this->hint = $hint;
|
$this->hint = $hint;
|
||||||
$this->redirectUri = $redirectUri;
|
$this->redirectUri = $redirectUri;
|
||||||
|
$this->payload = [
|
||||||
|
'error' => $errorType,
|
||||||
|
'message' => $message,
|
||||||
|
];
|
||||||
|
if ($hint !== null) {
|
||||||
|
$this->payload['hint'] = $hint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current payload.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPayload()
|
||||||
|
{
|
||||||
|
return $this->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current payload.
|
||||||
|
*
|
||||||
|
* @param array $payload
|
||||||
|
*/
|
||||||
|
public function setPayload(array $payload)
|
||||||
|
{
|
||||||
|
$this->payload = $payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +92,7 @@ class OAuthServerException extends \Exception
|
|||||||
public static function unsupportedGrantType()
|
public static function unsupportedGrantType()
|
||||||
{
|
{
|
||||||
$errorMessage = 'The authorization grant type is not supported by the authorization server.';
|
$errorMessage = 'The authorization grant type is not supported by the authorization server.';
|
||||||
$hint = 'Check the `grant_type` parameter';
|
$hint = 'Check that all required parameters have been provided';
|
||||||
|
|
||||||
return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
|
return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
|
||||||
}
|
}
|
||||||
@ -105,7 +137,15 @@ class OAuthServerException extends \Exception
|
|||||||
public static function invalidScope($scope, $redirectUri = null)
|
public static function invalidScope($scope, $redirectUri = null)
|
||||||
{
|
{
|
||||||
$errorMessage = 'The requested scope is invalid, unknown, or malformed';
|
$errorMessage = 'The requested scope is invalid, unknown, or malformed';
|
||||||
$hint = sprintf('Check the `%s` scope', $scope);
|
|
||||||
|
if (empty($scope)) {
|
||||||
|
$hint = 'Specify a scope in the request or set a default scope';
|
||||||
|
} else {
|
||||||
|
$hint = sprintf(
|
||||||
|
'Check the `%s` scope',
|
||||||
|
htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
|
return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
|
||||||
}
|
}
|
||||||
@ -123,7 +163,7 @@ class OAuthServerException extends \Exception
|
|||||||
/**
|
/**
|
||||||
* Server error.
|
* Server error.
|
||||||
*
|
*
|
||||||
* @param $hint
|
* @param string $hint
|
||||||
*
|
*
|
||||||
* @return static
|
* @return static
|
||||||
*
|
*
|
||||||
@ -149,7 +189,7 @@ class OAuthServerException extends \Exception
|
|||||||
*/
|
*/
|
||||||
public static function invalidRefreshToken($hint = null)
|
public static function invalidRefreshToken($hint = null)
|
||||||
{
|
{
|
||||||
return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint);
|
return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,21 +245,15 @@ class OAuthServerException extends \Exception
|
|||||||
*
|
*
|
||||||
* @param ResponseInterface $response
|
* @param ResponseInterface $response
|
||||||
* @param bool $useFragment True if errors should be in the URI fragment instead of query string
|
* @param bool $useFragment True if errors should be in the URI fragment instead of query string
|
||||||
|
* @param int $jsonOptions options passed to json_encode
|
||||||
*
|
*
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function generateHttpResponse(ResponseInterface $response, $useFragment = false)
|
public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
|
||||||
{
|
{
|
||||||
$headers = $this->getHttpHeaders();
|
$headers = $this->getHttpHeaders();
|
||||||
|
|
||||||
$payload = [
|
$payload = $this->getPayload();
|
||||||
'error' => $this->getErrorType(),
|
|
||||||
'message' => $this->getMessage(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->hint !== null) {
|
|
||||||
$payload['hint'] = $this->hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->redirectUri !== null) {
|
if ($this->redirectUri !== null) {
|
||||||
if ($useFragment === true) {
|
if ($useFragment === true) {
|
||||||
@ -235,7 +269,7 @@ class OAuthServerException extends \Exception
|
|||||||
$response = $response->withHeader($header, $content);
|
$response = $response->withHeader($header, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->getBody()->write(json_encode($payload));
|
$response->getBody()->write(json_encode($payload, $jsonOptions));
|
||||||
|
|
||||||
return $response->withStatus($this->getHttpStatusCode());
|
return $response->withStatus($this->getHttpStatusCode());
|
||||||
}
|
}
|
||||||
@ -260,13 +294,9 @@ class OAuthServerException extends \Exception
|
|||||||
// include the "WWW-Authenticate" response header field
|
// include the "WWW-Authenticate" response header field
|
||||||
// matching the authentication scheme used by the client.
|
// matching the authentication scheme used by the client.
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
if ($this->errorType === 'invalid_client') {
|
if ($this->errorType === 'invalid_client' && array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false) {
|
||||||
$authScheme = 'Basic';
|
$authScheme = strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0 ? 'Bearer' : 'Basic';
|
||||||
if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false
|
|
||||||
&& strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0
|
|
||||||
) {
|
|
||||||
$authScheme = 'Bearer';
|
|
||||||
}
|
|
||||||
$headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
|
$headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
|
||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
namespace League\OAuth2\Server\Grant;
|
namespace League\OAuth2\Server\Grant;
|
||||||
|
|
||||||
use League\Event\EmitterAwareTrait;
|
use League\Event\EmitterAwareTrait;
|
||||||
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\CryptTrait;
|
use League\OAuth2\Server\CryptTrait;
|
||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||||
@ -75,6 +76,16 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
*/
|
*/
|
||||||
protected $refreshTokenTTL;
|
protected $refreshTokenTTL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \League\OAuth2\Server\CryptKey
|
||||||
|
*/
|
||||||
|
protected $privateKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @string
|
||||||
|
*/
|
||||||
|
protected $defaultScope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ClientRepositoryInterface $clientRepository
|
* @param ClientRepositoryInterface $clientRepository
|
||||||
*/
|
*/
|
||||||
@ -131,6 +142,24 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the private key
|
||||||
|
*
|
||||||
|
* @param \League\OAuth2\Server\CryptKey $key
|
||||||
|
*/
|
||||||
|
public function setPrivateKey(CryptKey $key)
|
||||||
|
{
|
||||||
|
$this->privateKey = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $scope
|
||||||
|
*/
|
||||||
|
public function setDefaultScope($scope)
|
||||||
|
{
|
||||||
|
$this->defaultScope = $scope;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the client.
|
* Validate the client.
|
||||||
*
|
*
|
||||||
@ -175,7 +204,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
@ -195,18 +224,14 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
*
|
*
|
||||||
* @return ScopeEntityInterface[]
|
* @return ScopeEntityInterface[]
|
||||||
*/
|
*/
|
||||||
public function validateScopes(
|
public function validateScopes($scopes, $redirectUri = null)
|
||||||
$scopes,
|
{
|
||||||
$redirectUri = null
|
$scopesList = array_filter(explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), function ($scope) {
|
||||||
) {
|
|
||||||
$scopesList = array_filter(
|
|
||||||
explode(self::SCOPE_DELIMITER_STRING, trim($scopes)),
|
|
||||||
function ($scope) {
|
|
||||||
return !empty($scope);
|
return !empty($scope);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
$validScopes = [];
|
||||||
|
|
||||||
$scopes = [];
|
|
||||||
foreach ($scopesList as $scopeItem) {
|
foreach ($scopesList as $scopeItem) {
|
||||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
|
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
|
||||||
|
|
||||||
@ -214,10 +239,10 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes[] = $scope;
|
$validScopes[] = $scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $scopes;
|
return $validScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -316,7 +341,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
*
|
*
|
||||||
* @param \DateInterval $accessTokenTTL
|
* @param \DateInterval $accessTokenTTL
|
||||||
* @param ClientEntityInterface $client
|
* @param ClientEntityInterface $client
|
||||||
* @param string $userIdentifier
|
* @param string|null $userIdentifier
|
||||||
* @param ScopeEntityInterface[] $scopes
|
* @param ScopeEntityInterface[] $scopes
|
||||||
*
|
*
|
||||||
* @throws OAuthServerException
|
* @throws OAuthServerException
|
||||||
@ -361,7 +386,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
* @param \DateInterval $authCodeTTL
|
* @param \DateInterval $authCodeTTL
|
||||||
* @param ClientEntityInterface $client
|
* @param ClientEntityInterface $client
|
||||||
* @param string $userIdentifier
|
* @param string $userIdentifier
|
||||||
* @param string $redirectUri
|
* @param string|null $redirectUri
|
||||||
* @param ScopeEntityInterface[] $scopes
|
* @param ScopeEntityInterface[] $scopes
|
||||||
*
|
*
|
||||||
* @throws OAuthServerException
|
* @throws OAuthServerException
|
||||||
@ -382,7 +407,10 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
||||||
$authCode->setClient($client);
|
$authCode->setClient($client);
|
||||||
$authCode->setUserIdentifier($userIdentifier);
|
$authCode->setUserIdentifier($userIdentifier);
|
||||||
|
|
||||||
|
if ($redirectUri !== null) {
|
||||||
$authCode->setRedirectUri($redirectUri);
|
$authCode->setRedirectUri($redirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($scopes as $scope) {
|
foreach ($scopes as $scope) {
|
||||||
$authCode->addScope($scope);
|
$authCode->addScope($scope);
|
||||||
|
@ -134,6 +134,15 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
throw OAuthServerException::invalidRequest('code_verifier');
|
throw OAuthServerException::invalidRequest('code_verifier');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate code_verifier according to RFC-7636
|
||||||
|
// @see: https://tools.ietf.org/html/rfc7636#section-4.1
|
||||||
|
if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeVerifier) !== 1) {
|
||||||
|
throw OAuthServerException::invalidRequest(
|
||||||
|
'code_verifier',
|
||||||
|
'Code Verifier must follow the specifications of RFC-7636.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($authCodePayload->code_challenge_method) {
|
switch ($authCodePayload->code_challenge_method) {
|
||||||
case 'plain':
|
case 'plain':
|
||||||
if (hash_equals($codeVerifier, $authCodePayload->code_challenge) === false) {
|
if (hash_equals($codeVerifier, $authCodePayload->code_challenge) === false) {
|
||||||
@ -144,7 +153,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
case 'S256':
|
case 'S256':
|
||||||
if (
|
if (
|
||||||
hash_equals(
|
hash_equals(
|
||||||
urlencode(base64_encode(hash('sha256', $codeVerifier))),
|
strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_'),
|
||||||
$authCodePayload->code_challenge
|
$authCodePayload->code_challenge
|
||||||
) === false
|
) === false
|
||||||
) {
|
) {
|
||||||
@ -167,6 +176,10 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
|
||||||
|
// Send events to emitter
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
|
||||||
// Inject tokens into response type
|
// Inject tokens into response type
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
$responseType->setRefreshToken($refreshToken);
|
||||||
@ -209,6 +222,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
$request,
|
$request,
|
||||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (is_null($clientId)) {
|
if (is_null($clientId)) {
|
||||||
throw OAuthServerException::invalidRequest('client_id');
|
throw OAuthServerException::invalidRequest('client_id');
|
||||||
}
|
}
|
||||||
@ -226,6 +240,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
}
|
}
|
||||||
|
|
||||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
||||||
|
|
||||||
if ($redirectUri !== null) {
|
if ($redirectUri !== null) {
|
||||||
if (
|
if (
|
||||||
is_string($client->getRedirectUri())
|
is_string($client->getRedirectUri())
|
||||||
@ -235,18 +250,24 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
|
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
||||||
|
|| empty($client->getRedirectUri())) {
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
|
throw OAuthServerException::invalidClient();
|
||||||
|
} else {
|
||||||
|
$redirectUri = is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request),
|
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
||||||
is_array($client->getRedirectUri())
|
$redirectUri
|
||||||
? $client->getRedirectUri()[0]
|
|
||||||
: $client->getRedirectUri()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||||
@ -255,7 +276,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
||||||
$authorizationRequest->setClient($client);
|
$authorizationRequest->setClient($client);
|
||||||
$authorizationRequest->setRedirectUri($redirectUri);
|
$authorizationRequest->setRedirectUri($redirectUri);
|
||||||
|
|
||||||
|
if ($stateParameter !== null) {
|
||||||
$authorizationRequest->setState($stateParameter);
|
$authorizationRequest->setState($stateParameter);
|
||||||
|
}
|
||||||
|
|
||||||
$authorizationRequest->setScopes($scopes);
|
$authorizationRequest->setScopes($scopes);
|
||||||
|
|
||||||
if ($this->enableCodeExchangeProof === true) {
|
if ($this->enableCodeExchangeProof === true) {
|
||||||
@ -265,13 +290,23 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
}
|
}
|
||||||
|
|
||||||
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
||||||
if (in_array($codeChallengeMethod, ['plain', 'S256']) === false) {
|
|
||||||
|
if (in_array($codeChallengeMethod, ['plain', 'S256'], true) === false) {
|
||||||
throw OAuthServerException::invalidRequest(
|
throw OAuthServerException::invalidRequest(
|
||||||
'code_challenge_method',
|
'code_challenge_method',
|
||||||
'Code challenge method must be `plain` or `S256`'
|
'Code challenge method must be `plain` or `S256`'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate code_challenge according to RFC-7636
|
||||||
|
// @see: https://tools.ietf.org/html/rfc7636#section-4.2
|
||||||
|
if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeChallenge) !== 1) {
|
||||||
|
throw OAuthServerException::invalidRequest(
|
||||||
|
'code_challenged',
|
||||||
|
'Code challenge must follow the specifications of RFC-7636.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$authorizationRequest->setCodeChallenge($codeChallenge);
|
$authorizationRequest->setCodeChallenge($codeChallenge);
|
||||||
$authorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
|
$authorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
|
||||||
}
|
}
|
||||||
@ -304,14 +339,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
$authorizationRequest->getScopes()
|
$authorizationRequest->getScopes()
|
||||||
);
|
);
|
||||||
|
|
||||||
$response = new RedirectResponse();
|
$payload = [
|
||||||
$response->setRedirectUri(
|
|
||||||
$this->makeRedirectUri(
|
|
||||||
$finalRedirectUri,
|
|
||||||
[
|
|
||||||
'code' => $this->encrypt(
|
|
||||||
json_encode(
|
|
||||||
[
|
|
||||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||||
'redirect_uri' => $authCode->getRedirectUri(),
|
'redirect_uri' => $authCode->getRedirectUri(),
|
||||||
'auth_code_id' => $authCode->getIdentifier(),
|
'auth_code_id' => $authCode->getIdentifier(),
|
||||||
@ -320,7 +348,16 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||||
'code_challenge' => $authorizationRequest->getCodeChallenge(),
|
'code_challenge' => $authorizationRequest->getCodeChallenge(),
|
||||||
'code_challenge_method' => $authorizationRequest->getCodeChallengeMethod(),
|
'code_challenge_method' => $authorizationRequest->getCodeChallengeMethod(),
|
||||||
]
|
];
|
||||||
|
|
||||||
|
$response = new RedirectResponse();
|
||||||
|
$response->setRedirectUri(
|
||||||
|
$this->makeRedirectUri(
|
||||||
|
$finalRedirectUri,
|
||||||
|
[
|
||||||
|
'code' => $this->encrypt(
|
||||||
|
json_encode(
|
||||||
|
$payload
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'state' => $authorizationRequest->getState(),
|
'state' => $authorizationRequest->getState(),
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Grant;
|
namespace League\OAuth2\Server\Grant;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\RequestEvent;
|
||||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
@ -29,13 +30,16 @@ class ClientCredentialsGrant extends AbstractGrant
|
|||||||
) {
|
) {
|
||||||
// Validate request
|
// Validate request
|
||||||
$client = $this->validateClient($request);
|
$client = $this->validateClient($request);
|
||||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
|
||||||
|
|
||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);
|
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);
|
||||||
|
|
||||||
// Issue and persist access token
|
// Issue and persist access token
|
||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes);
|
||||||
|
|
||||||
|
// Send event to emitter
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
|
|
||||||
// Inject access token into response type
|
// Inject access token into response type
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Grant;
|
namespace League\OAuth2\Server\Grant;
|
||||||
|
|
||||||
|
use Defuse\Crypto\Key;
|
||||||
use League\Event\EmitterAwareInterface;
|
use League\Event\EmitterAwareInterface;
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
@ -119,6 +120,13 @@ interface GrantTypeInterface extends EmitterAwareInterface
|
|||||||
*/
|
*/
|
||||||
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
|
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default scope.
|
||||||
|
*
|
||||||
|
* @param string $scope
|
||||||
|
*/
|
||||||
|
public function setDefaultScope($scope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the path to the private key.
|
* Set the path to the private key.
|
||||||
*
|
*
|
||||||
@ -127,9 +135,9 @@ interface GrantTypeInterface extends EmitterAwareInterface
|
|||||||
public function setPrivateKey(CryptKey $privateKey);
|
public function setPrivateKey(CryptKey $privateKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the path to the public key.
|
* Set the encryption key
|
||||||
*
|
*
|
||||||
* @param CryptKey $publicKey
|
* @param string|Key|null $key
|
||||||
*/
|
*/
|
||||||
public function setPublicKey(CryptKey $publicKey);
|
public function setEncryptionKey($key = null);
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,18 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
private $accessTokenTTL;
|
private $accessTokenTTL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \DateInterval $accessTokenTTL
|
* @var string
|
||||||
*/
|
*/
|
||||||
public function __construct(\DateInterval $accessTokenTTL)
|
private $queryDelimiter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateInterval $accessTokenTTL
|
||||||
|
* @param string $queryDelimiter
|
||||||
|
*/
|
||||||
|
public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#')
|
||||||
{
|
{
|
||||||
$this->accessTokenTTL = $accessTokenTTL;
|
$this->accessTokenTTL = $accessTokenTTL;
|
||||||
|
$this->queryDelimiter = $queryDelimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,7 +102,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
|
public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
array_key_exists('response_type', $request->getQueryParams())
|
isset($request->getQueryParams()['response_type'])
|
||||||
&& $request->getQueryParams()['response_type'] === 'token'
|
&& $request->getQueryParams()['response_type'] === 'token'
|
||||||
&& isset($request->getQueryParams()['client_id'])
|
&& isset($request->getQueryParams()['client_id'])
|
||||||
);
|
);
|
||||||
@ -137,22 +144,28 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
} elseif (
|
} elseif (
|
||||||
is_array($client->getRedirectUri())
|
is_array($client->getRedirectUri())
|
||||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
&& in_array($redirectUri, $client->getRedirectUri(), true) === false
|
||||||
) {
|
) {
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
throw OAuthServerException::invalidClient();
|
throw OAuthServerException::invalidClient();
|
||||||
}
|
}
|
||||||
|
} elseif (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1
|
||||||
|
|| empty($client->getRedirectUri())) {
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||||
|
throw OAuthServerException::invalidClient();
|
||||||
|
} else {
|
||||||
|
$redirectUri = is_array($client->getRedirectUri())
|
||||||
|
? $client->getRedirectUri()[0]
|
||||||
|
: $client->getRedirectUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopes = $this->validateScopes(
|
$scopes = $this->validateScopes(
|
||||||
$this->getQueryStringParameter('scope', $request),
|
$this->getQueryStringParameter('scope', $request, $this->defaultScope),
|
||||||
is_array($client->getRedirectUri())
|
$redirectUri
|
||||||
? $client->getRedirectUri()[0]
|
|
||||||
: $client->getRedirectUri()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
$scopes = $this->scopeRepository->finalizeScopes(
|
$finalizedScopes = $this->scopeRepository->finalizeScopes(
|
||||||
$scopes,
|
$scopes,
|
||||||
$this->getIdentifier(),
|
$this->getIdentifier(),
|
||||||
$client
|
$client
|
||||||
@ -164,8 +177,12 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
||||||
$authorizationRequest->setClient($client);
|
$authorizationRequest->setClient($client);
|
||||||
$authorizationRequest->setRedirectUri($redirectUri);
|
$authorizationRequest->setRedirectUri($redirectUri);
|
||||||
|
|
||||||
|
if ($stateParameter !== null) {
|
||||||
$authorizationRequest->setState($stateParameter);
|
$authorizationRequest->setState($stateParameter);
|
||||||
$authorizationRequest->setScopes($scopes);
|
}
|
||||||
|
|
||||||
|
$authorizationRequest->setScopes($finalizedScopes);
|
||||||
|
|
||||||
return $authorizationRequest;
|
return $authorizationRequest;
|
||||||
}
|
}
|
||||||
@ -200,11 +217,11 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
|||||||
$finalRedirectUri,
|
$finalRedirectUri,
|
||||||
[
|
[
|
||||||
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
||||||
'token_type' => 'bearer',
|
'token_type' => 'Bearer',
|
||||||
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(),
|
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(),
|
||||||
'state' => $authorizationRequest->getState(),
|
'state' => $authorizationRequest->getState(),
|
||||||
],
|
],
|
||||||
'#'
|
$this->queryDelimiter
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,16 +49,20 @@ class PasswordGrant extends AbstractGrant
|
|||||||
) {
|
) {
|
||||||
// Validate request
|
// Validate request
|
||||||
$client = $this->validateClient($request);
|
$client = $this->validateClient($request);
|
||||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));
|
||||||
$user = $this->validateUser($request, $client);
|
$user = $this->validateUser($request, $client);
|
||||||
|
|
||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
||||||
|
|
||||||
// Issue and persist new tokens
|
// Issue and persist new tokens
|
||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
|
||||||
|
// Send events to emitter
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
|
||||||
// Inject tokens into response
|
// Inject tokens into response
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
$responseType->setRefreshToken($refreshToken);
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\Grant;
|
namespace League\OAuth2\Server\Grant;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\RequestEvent;
|
use League\OAuth2\Server\RequestEvent;
|
||||||
@ -44,30 +43,19 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
// Validate request
|
// Validate request
|
||||||
$client = $this->validateClient($request);
|
$client = $this->validateClient($request);
|
||||||
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
|
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
|
||||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
$scopes = $this->validateScopes($this->getRequestParameter(
|
||||||
|
'scope',
|
||||||
|
$request,
|
||||||
|
implode(self::SCOPE_DELIMITER_STRING, $oldRefreshToken['scopes']))
|
||||||
|
);
|
||||||
|
|
||||||
// If no new scopes are requested then give the access token the original session scopes
|
|
||||||
if (count($scopes) === 0) {
|
|
||||||
$scopes = array_map(function ($scopeId) use ($client) {
|
|
||||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
|
||||||
|
|
||||||
if ($scope instanceof ScopeEntityInterface === false) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw OAuthServerException::invalidScope($scopeId);
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
return $scope;
|
|
||||||
}, $oldRefreshToken['scopes']);
|
|
||||||
} else {
|
|
||||||
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
||||||
// the request doesn't include any new scopes
|
// the request doesn't include any new scopes
|
||||||
foreach ($scopes as $scope) {
|
foreach ($scopes as $scope) {
|
||||||
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) {
|
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes'], true) === false) {
|
||||||
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Expire old tokens
|
// Expire old tokens
|
||||||
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
||||||
@ -77,6 +65,10 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
|
||||||
|
// Send events to emitter
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
|
||||||
// Inject tokens into response
|
// Inject tokens into response
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
$responseType->setRefreshToken($refreshToken);
|
||||||
@ -102,7 +94,7 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
// Validate refresh token
|
// Validate refresh token
|
||||||
try {
|
try {
|
||||||
$refreshToken = $this->decrypt($encryptedRefreshToken);
|
$refreshToken = $this->decrypt($encryptedRefreshToken);
|
||||||
} catch (\LogicException $e) {
|
} catch (\Exception $e) {
|
||||||
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token');
|
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Repositories;
|
|||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access token interface.
|
* Access token interface.
|
||||||
@ -33,6 +34,8 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface
|
|||||||
* Persists a new access token to permanent storage.
|
* Persists a new access token to permanent storage.
|
||||||
*
|
*
|
||||||
* @param AccessTokenEntityInterface $accessTokenEntity
|
* @param AccessTokenEntityInterface $accessTokenEntity
|
||||||
|
*
|
||||||
|
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||||
*/
|
*/
|
||||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity);
|
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
namespace League\OAuth2\Server\Repositories;
|
namespace League\OAuth2\Server\Repositories;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auth code storage interface.
|
* Auth code storage interface.
|
||||||
@ -27,6 +28,8 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface
|
|||||||
* Persists a new auth code to permanent storage.
|
* Persists a new auth code to permanent storage.
|
||||||
*
|
*
|
||||||
* @param AuthCodeEntityInterface $authCodeEntity
|
* @param AuthCodeEntityInterface $authCodeEntity
|
||||||
|
*
|
||||||
|
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||||
*/
|
*/
|
||||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
|
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
|
||||||
|
|
||||||
|
@ -20,12 +20,12 @@ interface ClientRepositoryInterface extends RepositoryInterface
|
|||||||
* Get a client.
|
* Get a client.
|
||||||
*
|
*
|
||||||
* @param string $clientIdentifier The client's identifier
|
* @param string $clientIdentifier The client's identifier
|
||||||
* @param string $grantType The grant type used
|
* @param null|string $grantType The grant type used (if sent)
|
||||||
* @param null|string $clientSecret The client's secret (if sent)
|
* @param null|string $clientSecret The client's secret (if sent)
|
||||||
* @param bool $mustValidateSecret If true the client must attempt to validate the secret if the client
|
* @param bool $mustValidateSecret If true the client must attempt to validate the secret if the client
|
||||||
* is confidential
|
* is confidential
|
||||||
*
|
*
|
||||||
* @return ClientEntityInterface
|
* @return ClientEntityInterface
|
||||||
*/
|
*/
|
||||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true);
|
public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
namespace League\OAuth2\Server\Repositories;
|
namespace League\OAuth2\Server\Repositories;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh token interface.
|
* Refresh token interface.
|
||||||
@ -27,6 +28,8 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface
|
|||||||
* Create a new refresh token_name.
|
* Create a new refresh token_name.
|
||||||
*
|
*
|
||||||
* @param RefreshTokenEntityInterface $refreshTokenEntity
|
* @param RefreshTokenEntityInterface $refreshTokenEntity
|
||||||
|
*
|
||||||
|
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||||
*/
|
*/
|
||||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity);
|
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity);
|
||||||
|
|
||||||
|
@ -18,6 +18,9 @@ class RequestEvent extends Event
|
|||||||
const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
|
const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
|
||||||
const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
|
const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
|
||||||
|
|
||||||
|
const REFRESH_TOKEN_ISSUED = 'refresh_token.issued';
|
||||||
|
const ACCESS_TOKEN_ISSUED = 'access_token.issued';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ServerRequestInterface
|
* @var ServerRequestInterface
|
||||||
*/
|
*/
|
||||||
|
@ -53,14 +53,14 @@ class AuthorizationRequest
|
|||||||
/**
|
/**
|
||||||
* The redirect URI used in the request
|
* The redirect URI used in the request
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string|null
|
||||||
*/
|
*/
|
||||||
protected $redirectUri;
|
protected $redirectUri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state parameter on the authorization request
|
* The state parameter on the authorization request
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string|null
|
||||||
*/
|
*/
|
||||||
protected $state;
|
protected $state;
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ class AuthorizationRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getRedirectUri()
|
public function getRedirectUri()
|
||||||
{
|
{
|
||||||
@ -167,7 +167,7 @@ class AuthorizationRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $redirectUri
|
* @param string|null $redirectUri
|
||||||
*/
|
*/
|
||||||
public function setRedirectUri($redirectUri)
|
public function setRedirectUri($redirectUri)
|
||||||
{
|
{
|
||||||
@ -175,7 +175,7 @@ class AuthorizationRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getState()
|
public function getState()
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,9 @@ class ResourceServer
|
|||||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->authorizationValidator instanceof BearerTokenValidator === true) {
|
||||||
$this->authorizationValidator->setPublicKey($this->publicKey);
|
$this->authorizationValidator->setPublicKey($this->publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->authorizationValidator;
|
return $this->authorizationValidator;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\ResponseTypes;
|
namespace League\OAuth2\Server\ResponseTypes;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\CryptKey;
|
||||||
use League\OAuth2\Server\CryptTrait;
|
use League\OAuth2\Server\CryptTrait;
|
||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
@ -29,6 +30,11 @@ abstract class AbstractResponseType implements ResponseTypeInterface
|
|||||||
*/
|
*/
|
||||||
protected $refreshToken;
|
protected $refreshToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CryptKey
|
||||||
|
*/
|
||||||
|
protected $privateKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -44,4 +50,14 @@ abstract class AbstractResponseType implements ResponseTypeInterface
|
|||||||
{
|
{
|
||||||
$this->refreshToken = $refreshToken;
|
$this->refreshToken = $refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the private key
|
||||||
|
*
|
||||||
|
* @param \League\OAuth2\Server\CryptKey $key
|
||||||
|
*/
|
||||||
|
public function setPrivateKey(CryptKey $key)
|
||||||
|
{
|
||||||
|
$this->privateKey = $key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace League\OAuth2\Server\ResponseTypes;
|
namespace League\OAuth2\Server\ResponseTypes;
|
||||||
|
|
||||||
|
use Defuse\Crypto\Key;
|
||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
@ -33,4 +34,11 @@ interface ResponseTypeInterface
|
|||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function generateHttpResponse(ResponseInterface $response);
|
public function generateHttpResponse(ResponseInterface $response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the encryption key
|
||||||
|
*
|
||||||
|
* @param string|Key|null $key
|
||||||
|
*/
|
||||||
|
public function setEncryptionKey($key = null);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace LeagueTests;
|
namespace LeagueTests;
|
||||||
|
|
||||||
use League\OAuth2\Server\AuthorizationServer;
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
use League\OAuth2\Server\CryptKey;
|
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||||
@ -17,15 +16,27 @@ use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
|||||||
use LeagueTests\Stubs\AccessTokenEntity;
|
use LeagueTests\Stubs\AccessTokenEntity;
|
||||||
use LeagueTests\Stubs\AuthCodeEntity;
|
use LeagueTests\Stubs\AuthCodeEntity;
|
||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
use Zend\Diactoros\ServerRequestFactory;
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
|
||||||
class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
class AuthorizationServerTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
// Make sure the keys have the correct permissions.
|
||||||
|
chmod(__DIR__ . '/Stubs/private.key', 0600);
|
||||||
|
chmod(__DIR__ . '/Stubs/public.key', 0600);
|
||||||
|
chmod(__DIR__ . '/Stubs/private.key.crlf', 0600);
|
||||||
|
}
|
||||||
|
|
||||||
public function testRespondToRequestInvalidGrantType()
|
public function testRespondToRequestInvalidGrantType()
|
||||||
{
|
{
|
||||||
$server = new AuthorizationServer(
|
$server = new AuthorizationServer(
|
||||||
@ -33,7 +44,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
||||||
'file://' . __DIR__ . '/Stubs/private.key',
|
'file://' . __DIR__ . '/Stubs/private.key',
|
||||||
'file://' . __DIR__ . '/Stubs/public.key',
|
base64_encode(random_bytes(36)),
|
||||||
new StubResponseType()
|
new StubResponseType()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -52,7 +63,9 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepository->method('getClientEntity')->willReturn(new ClientEntity());
|
$clientRepository->method('getClientEntity')->willReturn(new ClientEntity());
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
@ -63,10 +76,11 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessTokenRepositoryMock,
|
$accessTokenRepositoryMock,
|
||||||
$scopeRepositoryMock,
|
$scopeRepositoryMock,
|
||||||
'file://' . __DIR__ . '/Stubs/private.key',
|
'file://' . __DIR__ . '/Stubs/private.key',
|
||||||
'file://' . __DIR__ . '/Stubs/public.key',
|
base64_encode(random_bytes(36)),
|
||||||
new StubResponseType()
|
new StubResponseType()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$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['grant_type'] = 'client_credentials';
|
||||||
@ -92,7 +106,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$method = $abstractGrantReflection->getMethod('getResponseType');
|
$method = $abstractGrantReflection->getMethod('getResponseType');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$this->assertTrue($method->invoke($server) instanceof BearerTokenResponse);
|
$this->assertInstanceOf(BearerTokenResponse::class, $method->invoke($server));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCompleteAuthorizationRequest()
|
public function testCompleteAuthorizationRequest()
|
||||||
@ -116,9 +130,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/Stubs/private.key'));
|
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/Stubs/public.key'));
|
|
||||||
|
|
||||||
$server->enableGrantType($grant);
|
$server->enableGrantType($grant);
|
||||||
|
|
||||||
$authRequest = new AuthorizationRequest();
|
$authRequest = new AuthorizationRequest();
|
||||||
@ -127,12 +138,59 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$authRequest->setGrantTypeId('authorization_code');
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
$authRequest->setUser(new UserEntity());
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
$this->assertTrue(
|
$this->assertInstanceOf(
|
||||||
$server->completeAuthorizationRequest($authRequest, new Response) instanceof ResponseInterface
|
ResponseInterface::class,
|
||||||
|
$server->completeAuthorizationRequest($authRequest, new Response)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidateAuthorizationRequest()
|
public function testValidateAuthorizationRequest()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
|
||||||
|
$server = new AuthorizationServer(
|
||||||
|
$clientRepositoryMock,
|
||||||
|
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
||||||
|
$scopeRepositoryMock,
|
||||||
|
'file://' . __DIR__ . '/Stubs/private.key',
|
||||||
|
'file://' . __DIR__ . '/Stubs/public.key'
|
||||||
|
);
|
||||||
|
|
||||||
|
$server->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
$server->enableGrantType($grant);
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'php://input',
|
||||||
|
$headers = [],
|
||||||
|
$cookies = [],
|
||||||
|
$queryParams = [
|
||||||
|
'response_type' => 'code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AuthorizationRequest::class, $server->validateAuthorizationRequest($request));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateAuthorizationRequestWithMissingRedirectUri()
|
||||||
{
|
{
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
@ -168,7 +226,12 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($server->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
try {
|
||||||
|
$server->validateAuthorizationRequest($request);
|
||||||
|
} catch (OAuthServerException $e) {
|
||||||
|
$this->assertEquals('invalid_client', $e->getErrorType());
|
||||||
|
$this->assertEquals(401, $e->getHttpStatusCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
40
tests/AuthorizationValidators/BearerTokenValidatorTest.php
Normal file
40
tests/AuthorizationValidators/BearerTokenValidatorTest.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace LeagueTests\AuthorizationValidators;
|
||||||
|
|
||||||
|
use Lcobucci\JWT\Builder;
|
||||||
|
use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
|
||||||
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
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();
|
||||||
|
|
||||||
|
$bearerTokenValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
|
$bearerTokenValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
|
$unsignedJwt = (new Builder())
|
||||||
|
->setAudience('client-id')
|
||||||
|
->setId('token-id', true)
|
||||||
|
->setIssuedAt(time())
|
||||||
|
->setNotBefore(time())
|
||||||
|
->setExpiration(time())
|
||||||
|
->setSubject('user-id')
|
||||||
|
->set('scopes', 'scope1 scope2 scope3 scope4')
|
||||||
|
->getToken();
|
||||||
|
|
||||||
|
$request = new ServerRequest();
|
||||||
|
$request = $request->withHeader('authorization', sprintf('Bearer %s', $unsignedJwt));
|
||||||
|
|
||||||
|
$bearerTokenValidator->validateAuthorization($request);
|
||||||
|
}
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace LeagueTests\Utils;
|
|
||||||
|
|
||||||
use League\OAuth2\Server\CryptKey;
|
|
||||||
use LeagueTests\Stubs\CryptTraitStub;
|
|
||||||
|
|
||||||
class CryptTraitTest extends \PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* CryptTrait stub
|
|
||||||
*/
|
|
||||||
protected $cryptStub;
|
|
||||||
|
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
$this->cryptStub = new CryptTraitStub;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEncryptDecrypt()
|
|
||||||
{
|
|
||||||
$payload = 'alex loves whisky';
|
|
||||||
$encrypted = $this->cryptStub->doEncrypt($payload);
|
|
||||||
$plainText = $this->cryptStub->doDecrypt($encrypted);
|
|
||||||
|
|
||||||
$this->assertNotEquals($payload, $encrypted);
|
|
||||||
$this->assertEquals($payload, $plainText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \LogicException
|
|
||||||
*/
|
|
||||||
public function testBadPrivateKey()
|
|
||||||
{
|
|
||||||
$this->cryptStub->setPrivateKey(new CryptKey(__DIR__ . '/Stubs/public.key'));
|
|
||||||
$this->cryptStub->doEncrypt('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \LogicException
|
|
||||||
*/
|
|
||||||
public function testBadPublicKey()
|
|
||||||
{
|
|
||||||
$this->cryptStub->setPublicKey(new CryptKey(__DIR__ . '/Stubs/private.key'));
|
|
||||||
$this->cryptStub->doDecrypt('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \LogicException
|
|
||||||
*/
|
|
||||||
public function testNonExistentKey()
|
|
||||||
{
|
|
||||||
new CryptKey('foo/bar');
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@
|
|||||||
namespace LeagueTests\Grant;
|
namespace LeagueTests\Grant;
|
||||||
|
|
||||||
use League\Event\Emitter;
|
use League\Event\Emitter;
|
||||||
use League\OAuth2\Server\CryptKey;
|
|
||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
@ -19,16 +18,15 @@ use LeagueTests\Stubs\AuthCodeEntity;
|
|||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
use LeagueTests\Stubs\RefreshTokenEntity;
|
use LeagueTests\Stubs\RefreshTokenEntity;
|
||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
class AbstractGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetSet()
|
public function testGetSet()
|
||||||
{
|
{
|
||||||
/** @var AbstractGrant $grantMock */
|
/** @var AbstractGrant $grantMock */
|
||||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||||
$grantMock->setPrivateKey(new CryptKey(__DIR__ . '/../Stubs/private.key'));
|
|
||||||
$grantMock->setPublicKey(new CryptKey(__DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grantMock->setEmitter(new Emitter());
|
$grantMock->setEmitter(new Emitter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +342,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessToken = new AccessTokenEntity();
|
$accessToken = new AccessTokenEntity();
|
||||||
/** @var RefreshTokenEntityInterface $refreshToken */
|
/** @var RefreshTokenEntityInterface $refreshToken */
|
||||||
$refreshToken = $issueRefreshTokenMethod->invoke($grantMock, $accessToken);
|
$refreshToken = $issueRefreshTokenMethod->invoke($grantMock, $accessToken);
|
||||||
$this->assertTrue($refreshToken instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $refreshToken);
|
||||||
$this->assertEquals($accessToken, $refreshToken->getAccessToken());
|
$this->assertEquals($accessToken, $refreshToken->getAccessToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +367,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
123,
|
123,
|
||||||
[new ScopeEntity()]
|
[new ScopeEntity()]
|
||||||
);
|
);
|
||||||
$this->assertTrue($accessToken instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIssueAuthCode()
|
public function testIssueAuthCode()
|
||||||
@ -385,7 +383,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode');
|
$issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode');
|
||||||
$issueAuthCodeMethod->setAccessible(true);
|
$issueAuthCodeMethod->setAccessible(true);
|
||||||
|
|
||||||
$this->assertTrue(
|
$this->assertInstanceOf(
|
||||||
|
AuthCodeEntityInterface::class,
|
||||||
$issueAuthCodeMethod->invoke(
|
$issueAuthCodeMethod->invoke(
|
||||||
$grantMock,
|
$grantMock,
|
||||||
new \DateInterval('PT1H'),
|
new \DateInterval('PT1H'),
|
||||||
@ -393,7 +392,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
123,
|
123,
|
||||||
'http://foo/bar',
|
'http://foo/bar',
|
||||||
[new ScopeEntity()]
|
[new ScopeEntity()]
|
||||||
) instanceof AuthCodeEntityInterface
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +468,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$method = $abstractGrantReflection->getMethod('generateUniqueIdentifier');
|
$method = $abstractGrantReflection->getMethod('generateUniqueIdentifier');
|
||||||
$method->setAccessible(true);
|
$method->setAccessible(true);
|
||||||
|
|
||||||
$this->assertTrue(is_string($method->invoke($grantMock)));
|
$this->assertInternalType('string', $method->invoke($grantMock));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCanRespondToAuthorizationRequest()
|
public function testCanRespondToAuthorizationRequest()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace LeagueTests\Grant;
|
namespace LeagueTests\Grant;
|
||||||
|
|
||||||
use League\OAuth2\Server\CryptKey;
|
|
||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
@ -23,15 +22,22 @@ use LeagueTests\Stubs\RefreshTokenEntity;
|
|||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
class AuthCodeGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var CryptTraitStub
|
* @var CryptTraitStub
|
||||||
*/
|
*/
|
||||||
protected $cryptStub;
|
protected $cryptStub;
|
||||||
|
|
||||||
|
const CODE_VERIFIER = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk';
|
||||||
|
|
||||||
|
const CODE_CHALLENGE = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM';
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$this->cryptStub = new CryptTraitStub;
|
$this->cryptStub = new CryptTraitStub;
|
||||||
@ -77,15 +83,22 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setRedirectUri('http://foo/bar');
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
|
||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -102,7 +115,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidateAuthorizationRequestRedirectUriArray()
|
public function testValidateAuthorizationRequestRedirectUriArray()
|
||||||
@ -112,12 +125,18 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -134,7 +153,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidateAuthorizationRequestCodeChallenge()
|
public function testValidateAuthorizationRequestCodeChallenge()
|
||||||
@ -144,6 +163,49 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->enableCodeExchangeProof();
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'response_type' => 'code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_challenge' => self::CODE_CHALLENGE,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
*/
|
||||||
|
public function testValidateAuthorizationRequestCodeChallengeInvalidLengthTooShort()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
@ -164,11 +226,85 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'response_type' => 'code',
|
'response_type' => 'code',
|
||||||
'client_id' => 'foo',
|
'client_id' => 'foo',
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_challenge' => 'FOOBAR',
|
'code_challenge' => str_repeat('A', 42),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
$grant->validateAuthorizationRequest($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
*/
|
||||||
|
public function testValidateAuthorizationRequestCodeChallengeInvalidLengthTooLong()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->enableCodeExchangeProof();
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'response_type' => 'code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_challenge' => str_repeat('A', 129),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->validateAuthorizationRequest($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
*/
|
||||||
|
public function testValidateAuthorizationRequestCodeChallengeInvalidCharacters()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->enableCodeExchangeProof();
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'response_type' => 'code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_challenge' => str_repeat('A', 42) . '!',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->validateAuthorizationRequest($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,6 +454,10 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
@ -325,6 +465,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
$grant->enableCodeExchangeProof();
|
$grant->enableCodeExchangeProof();
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -355,6 +497,10 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
|
||||||
$grant = new AuthCodeGrant(
|
$grant = new AuthCodeGrant(
|
||||||
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
@ -362,6 +508,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
$grant->enableCodeExchangeProof();
|
$grant->enableCodeExchangeProof();
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -399,11 +547,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -426,9 +572,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
|
|
||||||
$grant->completeAuthorizationRequest($authRequest);
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
}
|
}
|
||||||
@ -463,8 +607,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -497,8 +640,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToAccessTokenRequestCodeChallengePlain()
|
public function testRespondToAccessTokenRequestCodeChallengePlain()
|
||||||
@ -532,8 +675,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -548,7 +690,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'grant_type' => 'authorization_code',
|
'grant_type' => 'authorization_code',
|
||||||
'client_id' => 'foo',
|
'client_id' => 'foo',
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_verifier' => 'foobar',
|
'code_verifier' => self::CODE_VERIFIER,
|
||||||
'code' => $this->cryptStub->doEncrypt(
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
json_encode(
|
json_encode(
|
||||||
[
|
[
|
||||||
@ -558,7 +700,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'user_id' => 123,
|
'user_id' => 123,
|
||||||
'scopes' => ['foo'],
|
'scopes' => ['foo'],
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_challenge' => 'foobar',
|
'code_challenge' => self::CODE_VERIFIER,
|
||||||
'code_challenge_method' => 'plain',
|
'code_challenge_method' => 'plain',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -569,8 +711,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToAccessTokenRequestCodeChallengeS256()
|
public function testRespondToAccessTokenRequestCodeChallengeS256()
|
||||||
@ -604,8 +746,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -620,7 +761,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'grant_type' => 'authorization_code',
|
'grant_type' => 'authorization_code',
|
||||||
'client_id' => 'foo',
|
'client_id' => 'foo',
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_verifier' => 'foobar',
|
'code_verifier' => self::CODE_VERIFIER,
|
||||||
'code' => $this->cryptStub->doEncrypt(
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
json_encode(
|
json_encode(
|
||||||
[
|
[
|
||||||
@ -630,7 +771,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'user_id' => 123,
|
'user_id' => 123,
|
||||||
'scopes' => ['foo'],
|
'scopes' => ['foo'],
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_challenge' => urlencode(base64_encode(hash('sha256', 'foobar'))),
|
'code_challenge' => self::CODE_CHALLENGE,
|
||||||
'code_challenge_method' => 'S256',
|
'code_challenge_method' => 'S256',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -641,8 +782,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -662,7 +803,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -709,7 +850,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -762,8 +903,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -808,8 +948,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -872,8 +1011,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -933,8 +1071,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -994,8 +1131,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1053,8 +1189,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1069,7 +1204,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
'grant_type' => 'authorization_code',
|
'grant_type' => 'authorization_code',
|
||||||
'client_id' => 'foo',
|
'client_id' => 'foo',
|
||||||
'redirect_uri' => 'http://foo/bar',
|
'redirect_uri' => 'http://foo/bar',
|
||||||
'code_verifier' => 'nope',
|
'code_verifier' => self::CODE_VERIFIER,
|
||||||
'code' => $this->cryptStub->doEncrypt(
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
json_encode(
|
json_encode(
|
||||||
[
|
[
|
||||||
@ -1126,8 +1261,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1164,7 +1298,151 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/* @var StubResponseType $response */
|
/* @var StubResponseType $response */
|
||||||
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
} catch (OAuthServerException $e) {
|
} catch (OAuthServerException $e) {
|
||||||
$this->assertEquals($e->getHint(), 'Failed to verify `code_verifier`.');
|
$this->assertEquals($e->getHint(), 'Code Verifier must follow the specifications of RFC-7636.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRespondToAccessTokenRequestMalformedCodeVerifierS256WithInvalidChars()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setIdentifier('foo');
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeEntity = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->enableCodeExchangeProof();
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
'POST',
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'grant_type' => 'authorization_code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_verifier' => 'dqX7C-RbqjHYtytmhGTigKdZCXfxq-+xbsk9_GxUcaE', // Malformed code. Contains `+`.
|
||||||
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
|
json_encode(
|
||||||
|
[
|
||||||
|
'auth_code_id' => uniqid(),
|
||||||
|
'expire_time' => time() + 3600,
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'user_id' => 123,
|
||||||
|
'scopes' => ['foo'],
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_challenge' => self::CODE_CHALLENGE,
|
||||||
|
'code_challenge_method' => 'S256',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* @var StubResponseType $response */
|
||||||
|
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
} catch (OAuthServerException $e) {
|
||||||
|
$this->assertEquals($e->getHint(), 'Code Verifier must follow the specifications of RFC-7636.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRespondToAccessTokenRequestMalformedCodeVerifierS256WithInvalidLength()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setIdentifier('foo');
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeEntity = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->enableCodeExchangeProof();
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
'POST',
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'grant_type' => 'authorization_code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_verifier' => 'dqX7C-RbqjHY', // Malformed code. Invalid length.
|
||||||
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
|
json_encode(
|
||||||
|
[
|
||||||
|
'auth_code_id' => uniqid(),
|
||||||
|
'expire_time' => time() + 3600,
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'user_id' => 123,
|
||||||
|
'scopes' => ['foo'],
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code_challenge' => 'R7T1y1HPNFvs1WDCrx4lfoBS6KD2c71pr8OHvULjvv8',
|
||||||
|
'code_challenge_method' => 'S256',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* @var StubResponseType $response */
|
||||||
|
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
} catch (OAuthServerException $e) {
|
||||||
|
$this->assertEquals($e->getHint(), 'Code Verifier must follow the specifications of RFC-7636.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1199,8 +1477,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1259,11 +1536,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1287,11 +1562,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(),
|
||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1316,10 +1589,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
new \DateInterval('PT10M')
|
new \DateInterval('PT10M')
|
||||||
);
|
);
|
||||||
|
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRefreshTokenRepositoryUniqueConstraintCheck()
|
public function testRefreshTokenRepositoryUniqueConstraintCheck()
|
||||||
@ -1353,8 +1623,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1387,8 +1656,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1425,8 +1694,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1459,8 +1727,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1497,8 +1765,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -1531,8 +1798,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
/** @var StubResponseType $response */
|
/** @var StubResponseType $response */
|
||||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,11 +9,15 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
|||||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
use LeagueTests\Stubs\AccessTokenEntity;
|
use LeagueTests\Stubs\AccessTokenEntity;
|
||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase
|
class ClientCredentialsGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
public function testGetIdentifier()
|
public function testGetIdentifier()
|
||||||
{
|
{
|
||||||
$grant = new ClientCredentialsGrant();
|
$grant = new ClientCredentialsGrant();
|
||||||
@ -30,13 +34,16 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
$grant = new ClientCredentialsGrant();
|
$grant = new ClientCredentialsGrant();
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$serverRequest = new ServerRequest();
|
$serverRequest = new ServerRequest();
|
||||||
$serverRequest = $serverRequest->withParsedBody(
|
$serverRequest = $serverRequest->withParsedBody(
|
||||||
@ -49,6 +56,6 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$responseType = new StubResponseType();
|
$responseType = new StubResponseType();
|
||||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
$this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,13 @@ use LeagueTests\Stubs\CryptTraitStub;
|
|||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
class ImplicitGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CryptTrait stub
|
* CryptTrait stub
|
||||||
*/
|
*/
|
||||||
@ -96,6 +99,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -112,7 +116,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidateAuthorizationRequestRedirectUriArray()
|
public function testValidateAuthorizationRequestRedirectUriArray()
|
||||||
@ -130,6 +134,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$request = new ServerRequest(
|
$request = new ServerRequest(
|
||||||
[],
|
[],
|
||||||
@ -146,7 +151,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
$this->assertInstanceOf(AuthorizationRequest::class, $grant->validateAuthorizationRequest($request));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -283,10 +288,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,7 +311,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
$grant->completeAuthorizationRequest($authRequest);
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
@ -329,10 +332,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
$this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,7 +356,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
$grant->completeAuthorizationRequest($authRequest);
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
@ -379,7 +380,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
$grant->completeAuthorizationRequest($authRequest);
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
|
@ -13,12 +13,16 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
|||||||
use LeagueTests\Stubs\AccessTokenEntity;
|
use LeagueTests\Stubs\AccessTokenEntity;
|
||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
use LeagueTests\Stubs\RefreshTokenEntity;
|
use LeagueTests\Stubs\RefreshTokenEntity;
|
||||||
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class PasswordGrantTest extends \PHPUnit_Framework_TestCase
|
class PasswordGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
public function testGetIdentifier()
|
public function testGetIdentifier()
|
||||||
{
|
{
|
||||||
$userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock();
|
$userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock();
|
||||||
@ -46,13 +50,16 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
|
||||||
|
$scope = new ScopeEntity();
|
||||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
$grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock);
|
$grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
$serverRequest = new ServerRequest();
|
$serverRequest = new ServerRequest();
|
||||||
$serverRequest = $serverRequest->withParsedBody(
|
$serverRequest = $serverRequest->withParsedBody(
|
||||||
@ -67,8 +74,8 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$responseType = new StubResponseType();
|
$responseType = new StubResponseType();
|
||||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
$this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
$this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,12 +16,13 @@ use LeagueTests\Stubs\CryptTraitStub;
|
|||||||
use LeagueTests\Stubs\RefreshTokenEntity;
|
use LeagueTests\Stubs\RefreshTokenEntity;
|
||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
class RefreshTokenGrantTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* CryptTrait stub
|
* @var CryptTraitStub
|
||||||
*/
|
*/
|
||||||
protected $cryptStub;
|
protected $cryptStub;
|
||||||
|
|
||||||
@ -45,27 +46,24 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
|
||||||
$scopeEntity = new ScopeEntity();
|
$scopeEntity = new ScopeEntity();
|
||||||
|
$scopeEntity->setIdentifier('foo');
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
|
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
$accessTokenRepositoryMock
|
$accessTokenRepositoryMock->expects($this->once())->method('persistNewAccessToken')->willReturnSelf();
|
||||||
->expects($this->once())
|
|
||||||
->method('persistNewAccessToken')->willReturnSelf();
|
|
||||||
|
|
||||||
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
$refreshTokenRepositoryMock
|
$refreshTokenRepositoryMock->expects($this->once())->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
->expects($this->once())
|
|
||||||
->method('persistNewRefreshToken')->willReturnSelf();
|
|
||||||
|
|
||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
@ -82,19 +80,18 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$serverRequest = new ServerRequest();
|
$serverRequest = new ServerRequest();
|
||||||
$serverRequest = $serverRequest->withParsedBody(
|
$serverRequest = $serverRequest->withParsedBody([
|
||||||
[
|
|
||||||
'client_id' => 'foo',
|
'client_id' => 'foo',
|
||||||
'client_secret' => 'bar',
|
'client_secret' => 'bar',
|
||||||
'refresh_token' => $oldRefreshToken,
|
'refresh_token' => $oldRefreshToken,
|
||||||
]
|
'scopes' => ['foo'],
|
||||||
);
|
]);
|
||||||
|
|
||||||
$responseType = new StubResponseType();
|
$responseType = new StubResponseType();
|
||||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
$this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
$this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToReducedScopes()
|
public function testRespondToReducedScopes()
|
||||||
@ -121,7 +118,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
@ -150,8 +147,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$responseType = new StubResponseType();
|
$responseType = new StubResponseType();
|
||||||
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
$this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface);
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
$this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,7 +177,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setScopeRepository($scopeRepositoryMock);
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
@ -227,7 +224,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$serverRequest = new ServerRequest();
|
$serverRequest = new ServerRequest();
|
||||||
@ -259,7 +256,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = 'foobar';
|
$oldRefreshToken = 'foobar';
|
||||||
@ -291,14 +288,13 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
|
||||||
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
|
|
||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
@ -344,7 +340,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
@ -391,7 +387,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
$grant->setClientRepository($clientRepositoryMock);
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
|
@ -11,18 +11,24 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
|||||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
use LeagueTests\Stubs\AccessTokenEntity;
|
use LeagueTests\Stubs\AccessTokenEntity;
|
||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequestFactory;
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
|
||||||
class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
class AuthorizationServerMiddlewareTest extends TestCase
|
||||||
{
|
{
|
||||||
|
const DEFAULT_SCOPE = 'basic';
|
||||||
|
|
||||||
public function testValidResponse()
|
public function testValidResponse()
|
||||||
{
|
{
|
||||||
$clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
$clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
$clientRepository->method('getClientEntity')->willReturn(new ClientEntity());
|
$clientRepository->method('getClientEntity')->willReturn(new ClientEntity());
|
||||||
|
|
||||||
|
$scopeEntity = new ScopeEntity;
|
||||||
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
$accessRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
@ -33,10 +39,11 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessRepositoryMock,
|
$accessRepositoryMock,
|
||||||
$scopeRepositoryMock,
|
$scopeRepositoryMock,
|
||||||
'file://' . __DIR__ . '/../Stubs/private.key',
|
'file://' . __DIR__ . '/../Stubs/private.key',
|
||||||
'file://' . __DIR__ . '/../Stubs/public.key',
|
base64_encode(random_bytes(36)),
|
||||||
new StubResponseType()
|
new StubResponseType()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$server->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
$server->enableGrantType(new ClientCredentialsGrant());
|
$server->enableGrantType(new ClientCredentialsGrant());
|
||||||
|
|
||||||
$_POST['grant_type'] = 'client_credentials';
|
$_POST['grant_type'] = 'client_credentials';
|
||||||
@ -66,7 +73,7 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(),
|
||||||
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
$this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(),
|
||||||
'file://' . __DIR__ . '/../Stubs/private.key',
|
'file://' . __DIR__ . '/../Stubs/private.key',
|
||||||
'file://' . __DIR__ . '/../Stubs/public.key',
|
base64_encode(random_bytes(36)),
|
||||||
new StubResponseType()
|
new StubResponseType()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -97,7 +104,8 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
|||||||
$response = $exception->generateHttpResponse(new Response());
|
$response = $exception->generateHttpResponse(new Response());
|
||||||
|
|
||||||
$this->assertEquals(302, $response->getStatusCode());
|
$this->assertEquals(302, $response->getStatusCode());
|
||||||
$this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]);
|
$this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope',
|
||||||
|
$response->getHeader('location')[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOAuthErrorResponseRedirectUriFragment()
|
public function testOAuthErrorResponseRedirectUriFragment()
|
||||||
@ -106,6 +114,7 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
|||||||
$response = $exception->generateHttpResponse(new Response(), true);
|
$response = $exception->generateHttpResponse(new Response(), true);
|
||||||
|
|
||||||
$this->assertEquals(302, $response->getStatusCode());
|
$this->assertEquals(302, $response->getStatusCode());
|
||||||
$this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]);
|
$this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope',
|
||||||
|
$response->getHeader('location')[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,11 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
|||||||
use League\OAuth2\Server\ResourceServer;
|
use League\OAuth2\Server\ResourceServer;
|
||||||
use LeagueTests\Stubs\AccessTokenEntity;
|
use LeagueTests\Stubs\AccessTokenEntity;
|
||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
class ResourceServerMiddlewareTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testValidResponse()
|
public function testValidResponse()
|
||||||
{
|
{
|
||||||
|
39
tests/PHPStan/AbstractGrantExtension.php
Normal file
39
tests/PHPStan/AbstractGrantExtension.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace LeagueTests\PHPStan;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Grant\AbstractGrant;
|
||||||
|
use PhpParser\Node\Expr\MethodCall;
|
||||||
|
use PHPStan\Analyser\Scope;
|
||||||
|
use PHPStan\Reflection\MethodReflection;
|
||||||
|
use PHPStan\Type\DynamicMethodReturnTypeExtension;
|
||||||
|
use PHPStan\Type\NullType;
|
||||||
|
use PHPStan\Type\StringType;
|
||||||
|
use PHPStan\Type\Type;
|
||||||
|
use PHPStan\Type\TypeCombinator;
|
||||||
|
|
||||||
|
final class AbstractGrantExtension implements DynamicMethodReturnTypeExtension
|
||||||
|
{
|
||||||
|
public function getClass(): string
|
||||||
|
{
|
||||||
|
return AbstractGrant::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isMethodSupported(MethodReflection $methodReflection): bool
|
||||||
|
{
|
||||||
|
return in_array($methodReflection->getName(), [
|
||||||
|
'getRequestParameter',
|
||||||
|
'getQueryStringParameter',
|
||||||
|
'getCookieParameter',
|
||||||
|
], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
|
||||||
|
{
|
||||||
|
return TypeCombinator::union(...[
|
||||||
|
new StringType(),
|
||||||
|
isset($methodCall->args[2]) ? $scope->getType($methodCall->args[2]->value) : new NullType(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,10 @@ namespace LeagueTests;
|
|||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\ResourceServer;
|
use League\OAuth2\Server\ResourceServer;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequestFactory;
|
use Zend\Diactoros\ServerRequestFactory;
|
||||||
|
|
||||||
class ResourceServerTest extends \PHPUnit_Framework_TestCase
|
class ResourceServerTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testValidateAuthenticatedRequest()
|
public function testValidateAuthenticatedRequest()
|
||||||
{
|
{
|
||||||
|
@ -11,19 +11,18 @@ use LeagueTests\Stubs\AccessTokenEntity;
|
|||||||
use LeagueTests\Stubs\ClientEntity;
|
use LeagueTests\Stubs\ClientEntity;
|
||||||
use LeagueTests\Stubs\RefreshTokenEntity;
|
use LeagueTests\Stubs\RefreshTokenEntity;
|
||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
class BearerResponseTypeTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGenerateHttpResponse()
|
public function testGenerateHttpResponse()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier('clientName');
|
$client->setIdentifier('clientName');
|
||||||
@ -47,7 +46,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$response = $responseType->generateHttpResponse(new Response());
|
$response = $responseType->generateHttpResponse(new Response());
|
||||||
|
|
||||||
$this->assertTrue($response instanceof ResponseInterface);
|
$this->assertInstanceOf(ResponseInterface::class, $response);
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
$this->assertEquals('no-cache', $response->getHeader('pragma')[0]);
|
$this->assertEquals('no-cache', $response->getHeader('pragma')[0]);
|
||||||
$this->assertEquals('no-store', $response->getHeader('cache-control')[0]);
|
$this->assertEquals('no-store', $response->getHeader('cache-control')[0]);
|
||||||
@ -55,19 +54,17 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$response->getBody()->rewind();
|
$response->getBody()->rewind();
|
||||||
$json = json_decode($response->getBody()->getContents());
|
$json = json_decode($response->getBody()->getContents());
|
||||||
$this->assertEquals('Bearer', $json->token_type);
|
$this->assertAttributeEquals('Bearer', 'token_type', $json);
|
||||||
$this->assertTrue(isset($json->expires_in));
|
$this->assertObjectHasAttribute('expires_in', $json);
|
||||||
$this->assertTrue(isset($json->access_token));
|
$this->assertObjectHasAttribute('access_token', $json);
|
||||||
$this->assertTrue(isset($json->refresh_token));
|
$this->assertObjectHasAttribute('refresh_token', $json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGenerateHttpResponseWithExtraParams()
|
public function testGenerateHttpResponseWithExtraParams()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponseWithParams();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponseWithParams($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier('clientName');
|
$client->setIdentifier('clientName');
|
||||||
@ -91,7 +88,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$response = $responseType->generateHttpResponse(new Response());
|
$response = $responseType->generateHttpResponse(new Response());
|
||||||
|
|
||||||
$this->assertTrue($response instanceof ResponseInterface);
|
$this->assertInstanceOf(ResponseInterface::class, $response);
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
$this->assertEquals('no-cache', $response->getHeader('pragma')[0]);
|
$this->assertEquals('no-cache', $response->getHeader('pragma')[0]);
|
||||||
$this->assertEquals('no-store', $response->getHeader('cache-control')[0]);
|
$this->assertEquals('no-store', $response->getHeader('cache-control')[0]);
|
||||||
@ -99,23 +96,20 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$response->getBody()->rewind();
|
$response->getBody()->rewind();
|
||||||
$json = json_decode($response->getBody()->getContents());
|
$json = json_decode($response->getBody()->getContents());
|
||||||
$this->assertEquals('Bearer', $json->token_type);
|
$this->assertAttributeEquals('Bearer', 'token_type', $json);
|
||||||
$this->assertTrue(isset($json->expires_in));
|
$this->assertObjectHasAttribute('expires_in', $json);
|
||||||
$this->assertTrue(isset($json->access_token));
|
$this->assertObjectHasAttribute('access_token', $json);
|
||||||
$this->assertTrue(isset($json->refresh_token));
|
$this->assertObjectHasAttribute('refresh_token', $json);
|
||||||
|
|
||||||
$this->assertTrue(isset($json->foo));
|
$this->assertObjectHasAttribute('foo', $json);
|
||||||
$this->assertEquals('bar', $json->foo);
|
$this->assertAttributeEquals('bar', 'foo', $json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDetermineAccessTokenInHeaderValidToken()
|
public function testDetermineAccessTokenInHeaderValidToken()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier('clientName');
|
$client->setIdentifier('clientName');
|
||||||
@ -141,7 +135,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
||||||
|
|
||||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
$request = new ServerRequest();
|
$request = new ServerRequest();
|
||||||
@ -158,11 +151,10 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testDetermineAccessTokenInHeaderInvalidJWT()
|
public function testDetermineAccessTokenInHeaderInvalidJWT()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false);
|
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
$responseType = new BearerTokenResponse();
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier('clientName');
|
$client->setIdentifier('clientName');
|
||||||
@ -185,7 +177,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
$json = json_decode((string) $response->getBody());
|
$json = json_decode((string) $response->getBody());
|
||||||
|
|
||||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
$request = new ServerRequest();
|
$request = new ServerRequest();
|
||||||
@ -205,7 +196,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$responseType = new BearerTokenResponse();
|
$responseType = new BearerTokenResponse();
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
$client->setIdentifier('clientName');
|
$client->setIdentifier('clientName');
|
||||||
@ -231,7 +222,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true);
|
$accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true);
|
||||||
|
|
||||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
$request = new ServerRequest();
|
$request = new ServerRequest();
|
||||||
@ -249,16 +239,13 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testDetermineAccessTokenInHeaderInvalidToken()
|
public function testDetermineAccessTokenInHeaderInvalidToken()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
|
||||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
$request = new ServerRequest();
|
$request = new ServerRequest();
|
||||||
@ -276,16 +263,13 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testDetermineMissingBearerInHeader()
|
public function testDetermineMissingBearerInHeader()
|
||||||
{
|
{
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$responseType = new BearerTokenResponse();
|
||||||
|
|
||||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
|
||||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$responseType->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
|
||||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
|
||||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
$request = new ServerRequest();
|
$request = new ServerRequest();
|
||||||
|
1
tests/Stubs/.gitattributes
vendored
Normal file
1
tests/Stubs/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
private.key.crlf text eol=crlf
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace LeagueTests\Stubs;
|
namespace LeagueTests\Stubs;
|
||||||
|
|
||||||
use League\OAuth2\Server\CryptKey;
|
|
||||||
use League\OAuth2\Server\CryptTrait;
|
use League\OAuth2\Server\CryptTrait;
|
||||||
|
|
||||||
class CryptTraitStub
|
class CryptTraitStub
|
||||||
@ -11,8 +10,12 @@ class CryptTraitStub
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->setPrivateKey(new CryptKey('file://' . __DIR__ . '/private.key'));
|
$this->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
$this->setPublicKey(new CryptKey('file://' . __DIR__ . '/public.key'));
|
}
|
||||||
|
|
||||||
|
public function getKey()
|
||||||
|
{
|
||||||
|
return $this->encryptionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doEncrypt($unencryptedData)
|
public function doEncrypt($unencryptedData)
|
||||||
|
27
tests/Stubs/private.key.crlf
Normal file
27
tests/Stubs/private.key.crlf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAtHYxRBYATiiyDFs3pEhFg6Ei/UiQEmolTaQyQK810xHY23+X
|
||||||
|
4elLl6HP1J09mefmJ3ZdIgjIOS6rfK1BQnZIvI+IkoC7+qpD92y9f48iL0tCYKsn
|
||||||
|
i1LFFjP0bESTGDe7XANifQPkp9GvKgJbu7h1/ac8x4CBSU0ZjtEvinQRsdYil6OM
|
||||||
|
MXLWGozbBy13X8G+Ganv2i1aPZ2B25GyrH6lVIEwztGrSYxUrFVL+8dHhONf6PYX
|
||||||
|
19gjdzxkXCYQy2AGMc1FevZmnpIqDNQwX7CUUXQ4TDJmiP0aBEni094gUhnRFUr9
|
||||||
|
dmGpLQcCb2i0WMh2K+swFk3EutDAJ+73LKoZ3QIDAQABAoIBADo8Tge3xd9zGIoO
|
||||||
|
QbV9MRmaPW1ZJk0a/fDBRQpEwGzdvIqQ8VWQ8Lj9GdF18LQi9s3TT5i1FtAFNIfm
|
||||||
|
bUHiY/SdqSgF7SOmIIrPB5QLf6+dbM0/TmKSklFo8L6jnohZK9g0q2rGf9p8Ozem
|
||||||
|
TS4WB9WUS3PiD1a1T8Mb1Gisri0h7rvI4TIkrcx6lUUCgphCZd2TWUhmE3YmybOg
|
||||||
|
4h855W685g/ydzjwB+5Y6CS3V6a78Z5Gb4df3l0XfqCWh/xzuNs7nIpRv8CE0vRE
|
||||||
|
vq9j/cVyKkzMjiagteJaisTCBkDmtAi9dEVL8uaSDoTJq1g+VOGuJxHUm31Pavqr
|
||||||
|
3RwvXS0CgYEA74jUqmzxAwr/uBWquIkfMg+hsKjJe3gsSAJIAPzcA9OkzZd9w/1R
|
||||||
|
P8C92N2UaDbCW7ZEl7ZzS+IO6nA4OcR98j77/nBk6cYykyVRkSaj01epz3bRApxc
|
||||||
|
R18e49MBftSMnI5R7lIJO/UAIRfd0rntX4jkdVAdn9s/VOvG8w4KQXcCgYEAwN3W
|
||||||
|
b3azSNYlj4CW8+t6qS/3JQ/qpPgVuqkqP9dQXC9O6VlV03pJIwFk2Ldjd7/eXT+0
|
||||||
|
hFVB3O71iECfet/1UgustlgFp5I4ZrPmYF/J1nGpx1KIE8P4d0qC8lODtdnsGAcU
|
||||||
|
+/vBjXinX7pWgM8e6LAJzqNUq/xal/wNY325dEsCgYB7J0+n+/ECToJhhApNbHq0
|
||||||
|
g2LvcCh/Ka8iqsGYeGkqMoOWDKBlxvUiIRe6y1nFJvpQquqjUfP/fM+Ma3wM/2B9
|
||||||
|
zzJChEjuBK/2BYblaQdr3rN47i7R99BeBaLdIZywN9m/mFC5hkYnJHUXjqzG7j8E
|
||||||
|
El7bjgBdMx1hrQOR7ZMKSwKBgQC2SXXBiBlPwEdj6I/EH06h1hnrR63pGim/cN/j
|
||||||
|
0ye62WPmHW+HH888bLbaNgqnRgtvayS85rAHlzst+pZBVqfRUgN9nJhLl2IDgAlA
|
||||||
|
EYj9TBTBtXmz5MdUSHKXguO73yrMUvU8bOi1Q9I+IipcOGboWmoKikke/LbLa4lj
|
||||||
|
/ZJpHQKBgQCuDanU+AJKgUQkkC2gHwT8quxPoRcFFErHp3iaDAwd5XsZJG9FHQUP
|
||||||
|
RkPE+JkSaj65byFLhCPHUayfk4Y4udHEy4cXiv2SxZNK8q1HwuFEvb7uFprj0hNs
|
||||||
|
14qJunONVt/jzswdwO5kGVbpGlHl7U0JABnTJP71fW/rE5SH4zYxqg==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
@ -3,8 +3,9 @@
|
|||||||
namespace LeagueTests\Utils;
|
namespace LeagueTests\Utils;
|
||||||
|
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class CryptKeyTest extends \PHPUnit_Framework_TestCase
|
class CryptKeyTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @expectedException \LogicException
|
* @expectedException \LogicException
|
||||||
@ -16,7 +17,7 @@ class CryptKeyTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testKeyCreation()
|
public function testKeyCreation()
|
||||||
{
|
{
|
||||||
$keyFile = __DIR__ . '/Stubs/public.key';
|
$keyFile = __DIR__ . '/../Stubs/public.key';
|
||||||
$key = new CryptKey($keyFile, 'secret');
|
$key = new CryptKey($keyFile, 'secret');
|
||||||
|
|
||||||
$this->assertEquals('file://' . $keyFile, $key->getKeyPath());
|
$this->assertEquals('file://' . $keyFile, $key->getKeyPath());
|
||||||
@ -25,7 +26,15 @@ class CryptKeyTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testKeyFileCreation()
|
public function testKeyFileCreation()
|
||||||
{
|
{
|
||||||
$keyContent = file_get_contents(__DIR__ . '/Stubs/public.key');
|
$keyContent = file_get_contents(__DIR__ . '/../Stubs/public.key');
|
||||||
|
$key = new CryptKey($keyContent);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'file://' . sys_get_temp_dir() . '/' . sha1($keyContent) . '.key',
|
||||||
|
$key->getKeyPath()
|
||||||
|
);
|
||||||
|
|
||||||
|
$keyContent = file_get_contents(__DIR__ . '/../Stubs/private.key.crlf');
|
||||||
$key = new CryptKey($keyContent);
|
$key = new CryptKey($keyContent);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
41
tests/Utils/CryptTraitTest.php
Normal file
41
tests/Utils/CryptTraitTest.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace LeagueTests\Utils;
|
||||||
|
|
||||||
|
use Defuse\Crypto\Key;
|
||||||
|
use LeagueTests\Stubs\CryptTraitStub;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class CryptTraitTest extends TestCase
|
||||||
|
{
|
||||||
|
protected $cryptStub;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->cryptStub = new CryptTraitStub();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncryptDecryptWithPassword()
|
||||||
|
{
|
||||||
|
$this->cryptStub->setEncryptionKey(base64_encode(random_bytes(36)));
|
||||||
|
|
||||||
|
$this->encryptDecrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncryptDecryptWithKey()
|
||||||
|
{
|
||||||
|
$this->cryptStub->setEncryptionKey(Key::createNewRandomKey());
|
||||||
|
|
||||||
|
$this->encryptDecrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function encryptDecrypt()
|
||||||
|
{
|
||||||
|
$payload = 'alex loves whisky';
|
||||||
|
$encrypted = $this->cryptStub->doEncrypt($payload);
|
||||||
|
$plainText = $this->cryptStub->doDecrypt($encrypted);
|
||||||
|
|
||||||
|
$this->assertNotEquals($payload, $encrypted);
|
||||||
|
$this->assertEquals($payload, $plainText);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user