mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
148 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
68e4b1d390 | ||
|
5ee1583c5b | ||
|
66de05a395 | ||
|
df20da1235 | ||
|
7321622104 | ||
|
84187041bd | ||
|
9eccc40eb6 | ||
|
8b865cc523 | ||
|
9775c0076b | ||
|
b68ef973df | ||
|
c6e5f12a7c | ||
|
6b88cbeb13 | ||
|
64a0fcb3a6 | ||
|
78dbb267ed | ||
|
22e6a350dd | ||
|
c0936cc320 | ||
|
bb82651bec | ||
|
599c9aba75 | ||
|
4c6c189dff | ||
|
8e8aed1a50 | ||
|
4a4f4fe2d7 | ||
|
6b18a9441a | ||
|
44ff7b33a1 | ||
|
db055f790d | ||
|
d1bc4848c8 | ||
|
cf63403585 | ||
|
cdf43e498e | ||
|
a12fc98b0d | ||
|
019d285235 | ||
|
0bb968f413 | ||
|
88b19ad2d0 | ||
|
6856699cab | ||
|
72cd9a62e1 | ||
|
acf262f879 | ||
|
5241309bdb | ||
|
9a93dca05c | ||
|
a6b7a5cedc | ||
|
78b6bddc4d | ||
|
14b6761c0f | ||
|
7c61922f07 | ||
|
20535ad95b | ||
|
e885114714 | ||
|
f80d0d39a4 | ||
|
7bfd5b7d0d | ||
|
143a2e32f7 | ||
|
8f418cff08 | ||
|
fcec1f3442 | ||
|
46e7eef14e | ||
|
51f44fdf17 | ||
|
f8b2e80ef3 | ||
|
7045785d89 | ||
|
301ddc53c7 | ||
|
2a6f900323 | ||
|
fb8f47e868 | ||
|
5b192b3548 | ||
|
bf55ce1f73 | ||
|
4942585f4f | ||
|
1575128162 | ||
|
78c2067698 | ||
|
f765f134c9 | ||
|
257318e524 | ||
|
77737e7894 | ||
|
f007e25070 | ||
|
25c2e9b31b | ||
|
6ed9cbf701 | ||
|
7c35778316 | ||
|
f6f39698d9 | ||
|
3904767873 | ||
|
c3a7c418da | ||
|
af5a06098b | ||
|
6205611a71 | ||
|
9f3648039b | ||
|
08c356a1e1 | ||
|
70e32ce9bf | ||
|
94a1c18fa9 | ||
|
88b01b792a | ||
|
0178a837d4 | ||
|
2025bd6a30 | ||
|
e7f18911f3 | ||
|
8e8ac35dcb | ||
|
16ed4ea51c | ||
|
de635f826f | ||
|
3e8577f889 | ||
|
525b9b3d3e | ||
|
f7413c2f15 | ||
|
6e583fdf8a | ||
|
1de13cf892 | ||
|
1ad44d1ce0 | ||
|
b480373249 | ||
|
3ad97b4ef4 | ||
|
0490736861 | ||
|
abaf399f5f | ||
|
55c8df8312 | ||
|
c5db707e69 | ||
|
ed7f78179a | ||
|
6e92239dd7 | ||
|
f5d731def9 | ||
|
03815cec6d | ||
|
c71dc47459 | ||
|
3bcd8fc3f8 | ||
|
db6d4e0dc6 | ||
|
f19189a999 | ||
|
ec9c91cc11 | ||
|
c3457107ee | ||
|
a9f61fd3ed | ||
|
b78d8ca1d8 | ||
|
8f82e8ef86 | ||
|
d88e01c7dd | ||
|
d21374fb0b | ||
|
31e5f4d33c | ||
|
a773405adf | ||
|
ccc845b195 | ||
|
21cd917892 | ||
|
a2c418ee07 | ||
|
b220368583 | ||
|
2d26c38d6c | ||
|
eeaa68400f | ||
|
56c73d2427 | ||
|
f632fcc997 | ||
|
618d84ddcf | ||
|
ace42e89e0 | ||
|
c496df98e4 | ||
|
2496653968 | ||
|
abf66ef9c8 | ||
|
4b9ec488f4 | ||
|
726d879607 | ||
|
b256195421 | ||
|
c84ea1ea62 | ||
|
16685ccde4 | ||
|
7934c7bb53 | ||
|
c174b6fc65 | ||
|
75ced70248 | ||
|
5b7fdaeece | ||
|
430a752315 | ||
|
810544ec0a | ||
|
34a6b66b8c | ||
|
61738a7fe2 | ||
|
51184259d1 | ||
|
b21de11429 | ||
|
cf6e86c9d4 | ||
|
f6fdbc7142 | ||
|
7f7f45662a | ||
|
f92a68cc72 | ||
|
295d8ffa24 | ||
|
3d08140651 | ||
|
ec8a8393ee | ||
|
3869b8f406 | ||
|
d43391564c |
@@ -2,7 +2,6 @@ filter:
|
||||
excluded_paths:
|
||||
- tests/*
|
||||
- vendor/*
|
||||
- examples/*
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
@@ -21,8 +20,7 @@ checks:
|
||||
fix_doc_comments: true
|
||||
tools:
|
||||
external_code_coverage:
|
||||
timeout: 600
|
||||
runs: 3
|
||||
timeout: 1800
|
||||
php_code_coverage: false
|
||||
php_code_sniffer:
|
||||
config:
|
||||
@@ -34,4 +32,4 @@ tools:
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
php_cpd:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
|
@@ -7,6 +7,7 @@ cache:
|
||||
- vendor
|
||||
|
||||
php:
|
||||
- 5.5.9
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
@@ -20,5 +21,4 @@ script:
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- V5-WIP
|
||||
- master
|
71
CHANGELOG.md
71
CHANGELOG.md
@@ -1,6 +1,75 @@
|
||||
# Changelog
|
||||
|
||||
## 5.0.0-RC2 (released 2016-04-XX)
|
||||
## 5.1.0 (released 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 (released 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 (released 2016-04-18)
|
||||
|
||||
* `state` parameter is now correctly returned after implicit grant authorization
|
||||
* Small code and docblock improvements
|
||||
|
||||
## 5.0.1 (released 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 (released 2016-04-17)
|
||||
|
||||
Version 5 is a complete code rewrite.
|
||||
|
||||
* JWT support
|
||||
* PSR-7 support
|
||||
* Improved exception errors
|
||||
* Replace all occurrences of the term "Storage" with "Repository"
|
||||
* Simplify repositories
|
||||
* Entities conform to interfaces and use traits
|
||||
* Auth code grant updated
|
||||
* Allow support for public clients
|
||||
* 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:
|
||||
|
||||
* Renamed Server class to AuthorizationServer
|
||||
* Added ResourceServer class
|
||||
* Run unit tests again PHP 5.5.9 as it's the minimum supported version
|
||||
* Enable PHPUnit 5.0 support
|
||||
* Improved examples and documentation
|
||||
* Make it clearer that the implicit grant doesn't support refresh tokens
|
||||
* Improved refresh token validation errors
|
||||
* Fixed refresh token expiry date
|
||||
|
||||
## 5.0.0-RC2 (released 2016-04-10)
|
||||
|
||||
Changes since RC1:
|
||||
|
||||
* Allow multiple client redirect URIs (Issue #511)
|
||||
* Remove unused mac token interface (Issue #503)
|
||||
|
13
README.md
13
README.md
@@ -17,6 +17,13 @@ It supports out of the box the following grants:
|
||||
* Resource owner password credentials grant
|
||||
* Refresh grant
|
||||
|
||||
The following RFCs are implemented:
|
||||
|
||||
* [RFC6749 "OAuth 2.0"](https://tools.ietf.org/html/rfc6749)
|
||||
* [RFC6750 " The OAuth 2.0 Authorization Framework: Bearer Token Usage"](https://tools.ietf.org/html/rfc6750)
|
||||
* [RFC7519 "JSON Web Token (JWT)"](https://tools.ietf.org/html/rfc7519)
|
||||
* [RFC7636 "Proof Key for Code Exchange by OAuth Public Clients"](https://tools.ietf.org/html/rfc7636)
|
||||
|
||||
This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](https://twitter.com/alexbilbie).
|
||||
|
||||
## Requirements
|
||||
@@ -49,9 +56,13 @@ Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague
|
||||
|
||||
If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below.
|
||||
|
||||
## Commercial Support
|
||||
|
||||
If you would like help implementing this library into your existing platform, or would be interested in OAuth advice or training for you and your team please get in touch with [Glynde Labs](https://glyndelabs.com).
|
||||
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email hello@alexbilbie.com instead of using the issue tracker.
|
||||
If you discover any security related issues, please email `hello@alexbilbie.com` instead of using the issue tracker.
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -8,12 +8,13 @@
|
||||
"ext-openssl": "*",
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^1.1",
|
||||
"paragonie/random_compat": "^1.1 || ^2.0",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"zendframework/zend-diactoros": "^1.0"
|
||||
"phpunit/phpunit": "^4.8 || ^5.0",
|
||||
"zendframework/zend-diactoros": "^1.0",
|
||||
"indigophp/hash-compat": "^1.1"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
@@ -63,5 +64,8 @@
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"indigophp/hash-compat": "Polyfill for hash_equals function for PHP 5.5"
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
## Installation
|
||||
|
||||
0. Run `composer install --no-dev` in this directory to install dependencies
|
||||
0. Run `composer install` in this directory to install dependencies
|
||||
0. Create a private key `openssl genrsa -out private.key 1024`
|
||||
0. Create a public key `openssl rsa -in private.key -pubout > public.key`
|
||||
0. `cd` into the public directory
|
||||
|
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": ".."
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"slim/slim": "3.0.*",
|
||||
"league/oauth2-server": "dev-V5-WIP"
|
||||
"slim/slim": "3.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^1.1",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OAuth2ServerExamples\\": "src/"
|
||||
"OAuth2ServerExamples\\": "src/",
|
||||
"League\\OAuth2\\Server\\": "../src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
452
examples/composer.lock
generated
452
examples/composer.lock
generated
@@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "ec2df46ff78a00052e1a241ce5988d81",
|
||||
"content-hash": "46a1c1e42c62d3e3645279fc54ae95b7",
|
||||
"hash": "48bcb7a3514d7c7f271c554ba1440124",
|
||||
"content-hash": "e41be75973527cb9d63f27ad14ac8624",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
@@ -34,243 +34,6 @@
|
||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||
"time": "2014-12-30 15:22:37"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5",
|
||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"mdanter/ecc": "~0.3",
|
||||
"mikey179/vfsstream": "~1.5",
|
||||
"phpmd/phpmd": "~2.2",
|
||||
"phpunit/php-invoker": "~1.1",
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"squizlabs/php_codesniffer": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"mdanter/ecc": "Required to use Elliptic Curves based algorithms."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lcobucci\\JWT\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Luís Otávio Cobucci Oblonczyk",
|
||||
"email": "lcobucci@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to work with JSON Web Token and JSON Web Signature",
|
||||
"keywords": [
|
||||
"JWS",
|
||||
"jwt"
|
||||
],
|
||||
"time": "2016-03-24 22:46:13"
|
||||
},
|
||||
{
|
||||
"name": "league/event",
|
||||
"version": "2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/event.git",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"henrikbjorn/phpspec-code-coverage": "~1.0.1",
|
||||
"phpspec/phpspec": "~2.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Event\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frenky.net"
|
||||
}
|
||||
],
|
||||
"description": "Event package",
|
||||
"keywords": [
|
||||
"emitter",
|
||||
"event",
|
||||
"listener"
|
||||
],
|
||||
"time": "2015-05-21 12:24:47"
|
||||
},
|
||||
{
|
||||
"name": "league/oauth2-server",
|
||||
"version": "dev-V5-authorization-request-flow",
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../",
|
||||
"reference": "5410a42bb66f5a61969c3ec1a8e7ab30d225875c",
|
||||
"shasum": null
|
||||
},
|
||||
"require": {
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"league/event": "^2.1",
|
||||
"paragonie/random_compat": "^1.1",
|
||||
"php": ">=5.5.9",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"replace": {
|
||||
"league/oauth2server": "*",
|
||||
"lncd/oauth2": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/plates": "^3.1",
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"zendframework/zend-diactoros": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"league/plates": "Used for parsing authorization code templates",
|
||||
"mustache/mustache": "Used for parsing authorization code templates",
|
||||
"smarty/smarty": "Used for parsing authorization code templates",
|
||||
"twig/twig": "Used for parsing authorization code templates"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "hello@alexbilbie.com",
|
||||
"homepage": "http://www.alexbilbie.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
|
||||
"homepage": "http://oauth2.thephpleague.com/",
|
||||
"keywords": [
|
||||
"api",
|
||||
"auth",
|
||||
"auth",
|
||||
"authentication",
|
||||
"authorisation",
|
||||
"authorization",
|
||||
"oauth",
|
||||
"oauth 2",
|
||||
"oauth 2.0",
|
||||
"oauth2",
|
||||
"protect",
|
||||
"resource",
|
||||
"secure",
|
||||
"server"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "league/plates",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/plates.git",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "~1.4.0",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~1.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Plates\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Reinink",
|
||||
"email": "jonathan@reinink.ca",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
|
||||
"homepage": "http://platesphp.com",
|
||||
"keywords": [
|
||||
"league",
|
||||
"package",
|
||||
"templates",
|
||||
"templating",
|
||||
"views"
|
||||
],
|
||||
"time": "2015-07-09 02:14:40"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v0.6.0",
|
||||
@@ -314,54 +77,6 @@
|
||||
],
|
||||
"time": "2015-06-18 19:15:47"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2016-03-18 20:34:03"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.0.2",
|
||||
@@ -524,12 +239,167 @@
|
||||
"time": "2015-12-07 14:11:09"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5",
|
||||
"reference": "afea8e682e911a21574fd8519321b32522fa25b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"mdanter/ecc": "~0.3",
|
||||
"mikey179/vfsstream": "~1.5",
|
||||
"phpmd/phpmd": "~2.2",
|
||||
"phpunit/php-invoker": "~1.1",
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"squizlabs/php_codesniffer": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"mdanter/ecc": "Required to use Elliptic Curves based algorithms."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lcobucci\\JWT\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Luís Otávio Cobucci Oblonczyk",
|
||||
"email": "lcobucci@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to work with JSON Web Token and JSON Web Signature",
|
||||
"keywords": [
|
||||
"JWS",
|
||||
"jwt"
|
||||
],
|
||||
"time": "2016-03-24 22:46:13"
|
||||
},
|
||||
{
|
||||
"name": "league/event",
|
||||
"version": "2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/event.git",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"henrikbjorn/phpspec-code-coverage": "~1.0.1",
|
||||
"phpspec/phpspec": "~2.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Event\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frenky.net"
|
||||
}
|
||||
],
|
||||
"description": "Event package",
|
||||
"keywords": [
|
||||
"emitter",
|
||||
"event",
|
||||
"listener"
|
||||
],
|
||||
"time": "2015-05-21 12:24:47"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2016-03-18 20:34:03"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"league/oauth2-server": 20
|
||||
},
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
|
@@ -1,9 +1,7 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Server;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
@@ -11,64 +9,65 @@ use Slim\App;
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
new ClientRepository(),
|
||||
new AccessTokenRepository(),
|
||||
new ScopeRepository(),
|
||||
'file://' . __DIR__ . '/../private.key',
|
||||
'file://' . __DIR__ . '/../public.key'
|
||||
// Add the resource server to the DI container
|
||||
ResourceServer::class => function () {
|
||||
$server = new ResourceServer(
|
||||
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
||||
'file://' . __DIR__ . '/../public.key' // the authorization server's public key
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
// Add the resource server middleware which will intercept and validate requests
|
||||
$app->add(
|
||||
new \League\OAuth2\Server\Middleware\ResourceServerMiddleware(
|
||||
$app->getContainer()->get(Server::class)
|
||||
$app->getContainer()->get(ResourceServer::class)
|
||||
)
|
||||
);
|
||||
|
||||
$app->get('/users', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
// An example endpoint secured with OAuth 2.0
|
||||
$app->get(
|
||||
'/users',
|
||||
function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
|
||||
$users = [
|
||||
[
|
||||
'id' => 123,
|
||||
'name' => 'Alex',
|
||||
'email' => 'alex@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 124,
|
||||
'name' => 'Frank',
|
||||
'email' => 'frank@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 125,
|
||||
'name' => 'Phil',
|
||||
'email' => 'phil@thephpleague.com',
|
||||
],
|
||||
];
|
||||
$users = [
|
||||
[
|
||||
'id' => 123,
|
||||
'name' => 'Alex',
|
||||
'email' => 'alex@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 124,
|
||||
'name' => 'Frank',
|
||||
'email' => 'frank@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 125,
|
||||
'name' => 'Phil',
|
||||
'email' => 'phil@thephpleague.com',
|
||||
],
|
||||
];
|
||||
|
||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['name']);
|
||||
// If the access token doesn't have the `basic` scope hide users' names
|
||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['email']);
|
||||
// If the access token doesn't have the `email` scope hide users' email addresses
|
||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['email']);
|
||||
}
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode($users));
|
||||
|
||||
return $response->withStatus(200);
|
||||
}
|
||||
);
|
||||
|
||||
$response->getBody()->write(json_encode($users));
|
||||
|
||||
return $response->withStatus(200);
|
||||
});
|
||||
|
||||
$app->run();
|
||||
$app->run();
|
@@ -1,9 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Entities\UserEntity;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
@@ -21,7 +27,7 @@ $app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
@@ -33,7 +39,7 @@ $app = new App([
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
@@ -56,8 +62,8 @@ $app = new App([
|
||||
]);
|
||||
|
||||
$app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
// Validate the HTTP request and return an AuthorizationRequest object.
|
||||
@@ -84,8 +90,8 @@ $app->get('/authorize', function (ServerRequestInterface $request, ResponseInter
|
||||
});
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
|
@@ -1,8 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
@@ -14,31 +20,33 @@ use Zend\Diactoros\Stream;
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$clientRepository = new ClientRepository(); // instance of ClientRepositoryInterface
|
||||
$scopeRepository = new ScopeRepository(); // instance of ScopeRepositoryInterface
|
||||
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
// Path to public and private keys
|
||||
$privateKey = 'file://'.__DIR__.'/../private.key';
|
||||
//$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
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
$privateKey,
|
||||
$publicKey
|
||||
);
|
||||
|
||||
// Enable the client credentials grant on the server with a token TTL of 1 hour
|
||||
// Enable the client credentials grant on the server
|
||||
$server->enableGrantType(
|
||||
new ClientCredentialsGrant(),
|
||||
new \DateInterval('PT1H')
|
||||
new \League\OAuth2\Server\Grant\ClientCredentialsGrant(),
|
||||
new \DateInterval('PT1H') // access tokens will expire after 1 hour
|
||||
);
|
||||
|
||||
return $server;
|
||||
@@ -46,14 +54,21 @@ $app = new App([
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
|
||||
// Try to respond to the request
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
|
||||
// All instances of OAuthServerException can be formatted into a HTTP response
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
|
||||
// Unknown exception
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
|
@@ -1,8 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ImplicitGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Entities\UserEntity;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
@@ -18,7 +25,7 @@ $app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
@@ -28,7 +35,7 @@ $app = new App([
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
@@ -44,8 +51,8 @@ $app = new App([
|
||||
]);
|
||||
|
||||
$app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
// Validate the HTTP request and return an AuthorizationRequest object.
|
||||
|
@@ -1,16 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
@@ -19,23 +25,22 @@ use Zend\Diactoros\Stream;
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
$userRepository = new UserRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
@@ -48,7 +53,6 @@ $app = new App([
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
$userRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
@@ -66,7 +70,7 @@ $app = new App([
|
||||
|
||||
// Access token issuer
|
||||
$app->post('/access_token', function () {
|
||||
})->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class)));
|
||||
})->add(new AuthorizationServerMiddleware($app->getContainer()->get(AuthorizationServer::class)));
|
||||
|
||||
// Secured API
|
||||
$app->group('/api', function () {
|
||||
@@ -90,6 +94,6 @@ $app->group('/api', function () {
|
||||
|
||||
return $response->withBody($body);
|
||||
});
|
||||
})->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class)));
|
||||
})->add(new ResourceServerMiddleware($app->getContainer()->get(AuthorizationServer::class)));
|
||||
|
||||
$app->run();
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
@@ -11,58 +11,64 @@ use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$userRepository = new UserRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
// Add the authorization server to the DI container
|
||||
AuthorizationServer::class => function () {
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
$server = new AuthorizationServer(
|
||||
new ClientRepository(), // instance of ClientRepositoryInterface
|
||||
new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface
|
||||
new ScopeRepository(), // instance of ScopeRepositoryInterface
|
||||
'file://'.__DIR__.'/../private.key', // path to private key
|
||||
'file://'.__DIR__.'/../public.key' // path to public key
|
||||
);
|
||||
|
||||
$grant = new PasswordGrant(
|
||||
new UserRepository(), // instance of UserRepositoryInterface
|
||||
new RefreshTokenRepository() // instance of RefreshTokenRepositoryInterface
|
||||
);
|
||||
$grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month
|
||||
|
||||
// Enable the password grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new PasswordGrant($userRepository, $refreshTokenRepository),
|
||||
new \DateInterval('PT1H')
|
||||
$grant,
|
||||
new \DateInterval('PT1H') // access tokens will expire after 1 hour
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
$app->post(
|
||||
'/access_token',
|
||||
function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
|
||||
try {
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
try {
|
||||
|
||||
// Try to respond to the access token request
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
|
||||
} catch (OAuthServerException $exception) {
|
||||
|
||||
// All instances of OAuthServerException can be converted to a PSR-7 response
|
||||
return $exception->generateHttpResponse($response);
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
|
||||
// Catch unexpected exceptions
|
||||
$body = $response->getBody();
|
||||
$body->write($exception->getMessage());
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
$app->run();
|
||||
|
@@ -1,8 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
@@ -18,7 +25,7 @@ $app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
@@ -29,7 +36,7 @@ $app = new App([
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
@@ -37,10 +44,13 @@ $app = new App([
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the refresh token grant on the server with a token TTL of 1 hour
|
||||
// Enable the refresh token grant on the server
|
||||
$grant = new RefreshTokenGrant($refreshTokenRepository);
|
||||
$grant->setRefreshTokenTTL(new \DateInterval('P1M')); // The refresh token will expire in 1 month
|
||||
|
||||
$server->enableGrantType(
|
||||
new RefreshTokenGrant($refreshTokenRepository),
|
||||
new \DateInterval('PT1H')
|
||||
$grant,
|
||||
new \DateInterval('PT1H') // The new access token will expire after 1 hour
|
||||
);
|
||||
|
||||
return $server;
|
||||
@@ -48,8 +58,8 @@ $app = new App([
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
@@ -10,13 +17,14 @@ class ClientRepository implements ClientRepositoryInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null)
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true)
|
||||
{
|
||||
$clients = [
|
||||
'myawesomeapp' => [
|
||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||
'name' => 'My Awesome App',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||
'name' => 'My Awesome App',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'is_confidential' => true,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -25,6 +33,14 @@ class ClientRepository implements ClientRepositoryInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
$mustValidateSecret === true
|
||||
&& $clients[$clientIdentifier]['is_confidential'] === true
|
||||
&& password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$client = new ClientEntity();
|
||||
$client->setIdentifier($clientIdentifier);
|
||||
$client->setName($clients[$clientIdentifier]['name']);
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
@@ -41,6 +48,13 @@ class ScopeRepository implements ScopeRepositoryInterface
|
||||
ClientEntityInterface $clientEntity,
|
||||
$userIdentifier = null
|
||||
) {
|
||||
// Example of programatically modifying the final scope of the access token
|
||||
if ((int) $userIdentifier === 1) {
|
||||
$scope = new ScopeEntity();
|
||||
$scope->setIdentifier('email');
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ScopeEntity;
|
||||
use OAuth2ServerExamples\Entities\UserEntity;
|
||||
|
||||
class UserRepository implements UserRepositoryInterface
|
||||
@@ -19,10 +25,6 @@ class UserRepository implements UserRepositoryInterface
|
||||
ClientEntityInterface $clientEntity
|
||||
) {
|
||||
if ($username === 'alex' && $password === 'whisky') {
|
||||
$scope = new ScopeEntity();
|
||||
$scope->setIdentifier('email');
|
||||
$scopes[] = $scope;
|
||||
|
||||
return new UserEntity();
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use DateInterval;
|
||||
use League\Event\EmitterAwareInterface;
|
||||
use League\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface;
|
||||
use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
@@ -18,7 +23,7 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class Server implements EmitterAwareInterface
|
||||
class AuthorizationServer implements EmitterAwareInterface
|
||||
{
|
||||
use EmitterAwareTrait;
|
||||
|
||||
@@ -62,21 +67,15 @@ class Server implements EmitterAwareInterface
|
||||
*/
|
||||
private $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface
|
||||
*/
|
||||
private $authorizationValidator;
|
||||
|
||||
/**
|
||||
* New server instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
|
||||
* @param \League\OAuth2\Server\CryptKey|string $privateKey
|
||||
* @param \League\OAuth2\Server\CryptKey|string $publicKey
|
||||
* @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
* @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator
|
||||
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
|
||||
* @param \League\OAuth2\Server\CryptKey|string $privateKey
|
||||
* @param \League\OAuth2\Server\CryptKey|string $publicKey
|
||||
* @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
*/
|
||||
public function __construct(
|
||||
ClientRepositoryInterface $clientRepository,
|
||||
@@ -84,8 +83,7 @@ class Server implements EmitterAwareInterface
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
$privateKey,
|
||||
$publicKey,
|
||||
ResponseTypeInterface $responseType = null,
|
||||
AuthorizationValidatorInterface $authorizationValidator = null
|
||||
ResponseTypeInterface $responseType = null
|
||||
) {
|
||||
$this->clientRepository = $clientRepository;
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
@@ -102,7 +100,6 @@ class Server implements EmitterAwareInterface
|
||||
$this->publicKey = $publicKey;
|
||||
|
||||
$this->responseType = $responseType;
|
||||
$this->authorizationValidator = $authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +156,7 @@ class Server implements EmitterAwareInterface
|
||||
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
*
|
||||
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
|
||||
{
|
||||
@@ -199,20 +196,6 @@ class Server implements EmitterAwareInterface
|
||||
throw OAuthServerException::unsupportedGrantType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token validity.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthenticatedRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->getAuthorizationValidator()->validateAuthorization($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token type that grants will return in the HTTP response.
|
||||
*
|
||||
@@ -221,25 +204,11 @@ class Server implements EmitterAwareInterface
|
||||
protected function getResponseType()
|
||||
{
|
||||
if (!$this->responseType instanceof ResponseTypeInterface) {
|
||||
$this->responseType = new BearerTokenResponse($this->accessTokenRepository);
|
||||
$this->responseType = new BearerTokenResponse();
|
||||
}
|
||||
|
||||
$this->responseType->setPrivateKey($this->privateKey);
|
||||
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface
|
||||
*/
|
||||
protected function getAuthorizationValidator()
|
||||
{
|
||||
if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) {
|
||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||
}
|
||||
|
||||
$this->authorizationValidator->setPublicKey($this->publicKey);
|
||||
|
||||
return $this->authorizationValidator;
|
||||
}
|
||||
}
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\AuthorizationValidators;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\AuthorizationValidators;
|
||||
|
||||
@@ -70,6 +77,9 @@ class BearerTokenValidator implements AuthorizationValidatorInterface
|
||||
} catch (\InvalidArgumentException $exception) {
|
||||
// JWT couldn't be parsed so return the request as is
|
||||
throw OAuthServerException::accessDenied($exception->getMessage());
|
||||
} catch(\RuntimeException $exception){
|
||||
//JWR couldn't be parsed so return the request as is
|
||||
throw OAuthServerException::accessDenied('Error while decoding to JSON');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
@@ -45,11 +52,4 @@ interface RefreshTokenEntityInterface
|
||||
* @return \League\OAuth2\Server\Entities\AccessTokenEntityInterface
|
||||
*/
|
||||
public function getAccessToken();
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired();
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
@@ -73,11 +80,4 @@ interface TokenInterface
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes();
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired();
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
@@ -6,6 +13,8 @@ use Lcobucci\JWT\Builder;
|
||||
use Lcobucci\JWT\Signer\Key;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
trait AccessTokenTrait
|
||||
{
|
||||
@@ -29,4 +38,24 @@ trait AccessTokenTrait
|
||||
->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
|
||||
->getToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
abstract public function getClient();
|
||||
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
abstract public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* @return string|int
|
||||
*/
|
||||
abstract public function getUserIdentifier();
|
||||
|
||||
/**
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
abstract public function getScopes();
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
@@ -52,14 +59,4 @@ trait RefreshTokenTrait
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return (new DateTime()) > $this->getExpiryDateTime();
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
@@ -107,14 +114,4 @@ trait TokenEntityTrait
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return (new DateTime()) > $this->getExpiryDateTime();
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
@@ -165,6 +172,26 @@ class OAuthServerException extends \Exception
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid grant.
|
||||
*
|
||||
* @param string $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidGrant($hint = '')
|
||||
{
|
||||
return new static(
|
||||
'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
|
||||
. 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
|
||||
. 'or was issued to another client.',
|
||||
10,
|
||||
'invalid_grant',
|
||||
400,
|
||||
$hint
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Ivan Kurnosov <zerkms@zerkms.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
|
||||
class UniqueTokenIdentifierConstraintViolationException extends OAuthServerException
|
||||
{
|
||||
public static function create()
|
||||
{
|
||||
$errorMessage = 'Could not create unique access token identifier';
|
||||
|
||||
return new static($errorMessage, 100, 'access_token_duplicate', 500);
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
@@ -35,10 +36,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
|
||||
const SCOPE_DELIMITER_STRING = ' ';
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
*/
|
||||
protected $request;
|
||||
const MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS = 10;
|
||||
|
||||
/**
|
||||
* @var ClientRepositoryInterface
|
||||
@@ -142,30 +140,25 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
$clientId = $this->getRequestParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
|
||||
|
||||
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing');
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
// If the client is confidential require the client secret
|
||||
$clientSecret = $this->getRequestParameter(
|
||||
'client_secret',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_PW', $request)
|
||||
);
|
||||
$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
$clientSecret
|
||||
$clientSecret,
|
||||
true
|
||||
);
|
||||
|
||||
if (!$client instanceof ClientEntityInterface) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
@@ -176,13 +169,13 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
} elseif (
|
||||
is_array($client->getRedirectUri())
|
||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
@@ -215,7 +208,7 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
foreach ($scopesList as $scopeItem) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
|
||||
|
||||
if (($scope instanceof ScopeEntityInterface) === false) {
|
||||
if (!$scope instanceof ScopeEntityInterface) {
|
||||
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
||||
}
|
||||
|
||||
@@ -241,6 +234,38 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve HTTP Basic Auth credentials with the Authorization header
|
||||
* of a request. First index of the returned array is the username,
|
||||
* second is the password (so list() will work). If the header does
|
||||
* not exist, or is otherwise an invalid HTTP Basic header, return
|
||||
* [null, null].
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @return string[]|null[]
|
||||
*/
|
||||
protected function getBasicAuthCredentials(ServerRequestInterface $request)
|
||||
{
|
||||
if (!$request->hasHeader('Authorization')) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
$header = $request->getHeader('Authorization')[0];
|
||||
if (strpos($header, 'Basic ') !== 0) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
if (!($decoded = base64_decode(substr($header, 6)))) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
if (strpos($decoded, ':') === false) {
|
||||
return [null, null]; // HTTP Basic header without colon isn't valid
|
||||
}
|
||||
|
||||
return explode(':', $decoded, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve query string parameter.
|
||||
*
|
||||
@@ -299,19 +324,28 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$userIdentifier,
|
||||
array $scopes = []
|
||||
) {
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL));
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
|
||||
return $accessToken;
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
return $accessToken;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,8 +366,9 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$redirectUri,
|
||||
array $scopes = []
|
||||
) {
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$authCode = $this->authCodeRepository->getNewAuthCode();
|
||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
@@ -343,9 +378,17 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$authCode->addScope($scope);
|
||||
}
|
||||
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
|
||||
return $authCode;
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
return $authCode;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,14 +398,23 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$refreshToken = $this->refreshTokenRepository->getNewRefreshToken();
|
||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
|
||||
return $refreshToken;
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
return $refreshToken;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,9 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
@@ -21,6 +29,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
*/
|
||||
private $authCodeTTL;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $enableCodeExchangeProof = false;
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
@@ -37,6 +50,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
public function enableCodeExchangeProof()
|
||||
{
|
||||
$this->enableCodeExchangeProof = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to an access token request.
|
||||
*
|
||||
@@ -90,7 +108,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
foreach ($authCodePayload->scopes as $scopeId) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if ($scope === false) {
|
||||
if (!$scope instanceof ScopeEntityInterface) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
@@ -100,11 +118,52 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
}
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $authCodePayload->user_id);
|
||||
$scopes = $this->scopeRepository->finalizeScopes(
|
||||
$scopes,
|
||||
$this->getIdentifier(),
|
||||
$client,
|
||||
$authCodePayload->user_id
|
||||
);
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code');
|
||||
}
|
||||
|
||||
// Validate code challenge
|
||||
if ($this->enableCodeExchangeProof === true) {
|
||||
$codeVerifier = $this->getRequestParameter('code_verifier', $request, null);
|
||||
if ($codeVerifier === null) {
|
||||
throw OAuthServerException::invalidRequest('code_verifier');
|
||||
}
|
||||
|
||||
switch ($authCodePayload->code_challenge_method) {
|
||||
case 'plain':
|
||||
if (hash_equals($codeVerifier, $authCodePayload->code_challenge) === false) {
|
||||
throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
|
||||
}
|
||||
|
||||
break;
|
||||
case 'S256':
|
||||
if (
|
||||
hash_equals(
|
||||
urlencode(base64_encode(hash('sha256', $codeVerifier))),
|
||||
$authCodePayload->code_challenge
|
||||
) === false
|
||||
) {
|
||||
throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
break;
|
||||
default:
|
||||
throw OAuthServerException::serverError(
|
||||
sprintf(
|
||||
'Unsupported code challenge method `%s`',
|
||||
$authCodePayload->code_challenge_method
|
||||
)
|
||||
);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
// Issue and persist access + refresh tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
@@ -157,11 +216,13 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier()
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
@@ -171,20 +232,22 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
} elseif (
|
||||
is_array($client->getRedirectUri())
|
||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
$client->getRedirectUri()
|
||||
is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
: $client->getRedirectUri()
|
||||
);
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
@@ -196,6 +259,24 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
$authorizationRequest->setState($stateParameter);
|
||||
$authorizationRequest->setScopes($scopes);
|
||||
|
||||
if ($this->enableCodeExchangeProof === true) {
|
||||
$codeChallenge = $this->getQueryStringParameter('code_challenge', $request);
|
||||
if ($codeChallenge === null) {
|
||||
throw OAuthServerException::invalidRequest('code_challenge');
|
||||
}
|
||||
|
||||
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
|
||||
if (in_array($codeChallengeMethod, ['plain', 'S256']) === false) {
|
||||
throw OAuthServerException::invalidRequest(
|
||||
'code_challenge_method',
|
||||
'Code challenge method must be `plain` or `S256`'
|
||||
);
|
||||
}
|
||||
|
||||
$authorizationRequest->setCodeChallenge($codeChallenge);
|
||||
$authorizationRequest->setCodeChallengeMethod($codeChallengeMethod);
|
||||
}
|
||||
|
||||
return $authorizationRequest;
|
||||
}
|
||||
|
||||
@@ -224,25 +305,27 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
$authorizationRequest->getScopes()
|
||||
);
|
||||
|
||||
$redirectPayload['code'] = $this->encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||
'redirect_uri' => $authCode->getRedirectUri(),
|
||||
'auth_code_id' => $authCode->getIdentifier(),
|
||||
'scopes' => $authCode->getScopes(),
|
||||
'user_id' => $authCode->getUserIdentifier(),
|
||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||
]
|
||||
)
|
||||
);
|
||||
$redirectPayload['state'] = $authorizationRequest->getState();
|
||||
|
||||
$response = new RedirectResponse();
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
$redirectPayload
|
||||
[
|
||||
'code' => $this->encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||
'redirect_uri' => $authCode->getRedirectUri(),
|
||||
'auth_code_id' => $authCode->getIdentifier(),
|
||||
'scopes' => $authCode->getScopes(),
|
||||
'user_id' => $authCode->getUserIdentifier(),
|
||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||
'code_challenge' => $authorizationRequest->getCodeChallenge(),
|
||||
'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(),
|
||||
]
|
||||
)
|
||||
),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
@@ -252,7 +335,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied(
|
||||
'The user denied the request',
|
||||
$finalRedirectUri
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\ResponseTypes\RedirectResponse;
|
||||
@@ -23,10 +31,29 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
*/
|
||||
public function __construct(\DateInterval $accessTokenTTL)
|
||||
{
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateInterval $refreshTokenTTL
|
||||
*
|
||||
* @throw \LogicException
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
||||
{
|
||||
throw new \LogicException('The Implicit Grant does not return refresh tokens');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*
|
||||
* @throw \LogicException
|
||||
*/
|
||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
throw new \LogicException('The Implicit Grant does not return refresh tokens');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -90,11 +117,13 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier()
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
@@ -104,20 +133,22 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
} elseif (
|
||||
is_array($client->getRedirectUri())
|
||||
&& in_array($redirectUri, $client->getRedirectUri()) === false
|
||||
) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
$client->getRedirectUri()
|
||||
is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
: $client->getRedirectUri()
|
||||
);
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
@@ -156,15 +187,16 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
$authorizationRequest->getScopes()
|
||||
);
|
||||
|
||||
$redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey);
|
||||
$redirectPayload['token_type'] = 'bearer';
|
||||
$redirectPayload['expires_in'] = $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp();
|
||||
|
||||
$response = new RedirectResponse();
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
$redirectPayload,
|
||||
[
|
||||
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
],
|
||||
'#'
|
||||
)
|
||||
);
|
||||
@@ -175,7 +207,12 @@ class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied(
|
||||
'The user denied the request',
|
||||
$finalRedirectUri
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -77,12 +77,12 @@ class PasswordGrant extends AbstractGrant
|
||||
{
|
||||
$username = $this->getRequestParameter('username', $request);
|
||||
if (is_null($username)) {
|
||||
throw OAuthServerException::invalidRequest('username', '`%s` parameter is missing');
|
||||
throw OAuthServerException::invalidRequest('username');
|
||||
}
|
||||
|
||||
$password = $this->getRequestParameter('password', $request);
|
||||
if (is_null($password)) {
|
||||
throw OAuthServerException::invalidRequest('password', '`%s` parameter is missing');
|
||||
throw OAuthServerException::invalidRequest('password');
|
||||
}
|
||||
|
||||
$user = $this->userRepository->getUserEntityByUserCredentials(
|
||||
@@ -92,7 +92,7 @@ class PasswordGrant extends AbstractGrant
|
||||
$client
|
||||
);
|
||||
if (!$user instanceof UserEntityInterface) {
|
||||
$this->getEmitter()->emit(new RequestEvent('user.authentication.failed', $request));
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
|
||||
|
||||
throw OAuthServerException::invalidCredentials();
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
@@ -49,7 +50,7 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
$scopes = array_map(function ($scopeId) use ($client) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if (!$scope) {
|
||||
if (!$scope instanceof ScopeEntityInterface) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
@@ -101,17 +102,13 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
try {
|
||||
$refreshToken = $this->decrypt($encryptedRefreshToken);
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage());
|
||||
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token');
|
||||
}
|
||||
|
||||
$refreshTokenData = json_decode($refreshToken, true);
|
||||
if ($refreshTokenData['client_id'] !== $clientId) {
|
||||
$this->getEmitter()->emit(new RequestEvent('refresh_token.client.failed', $request));
|
||||
throw OAuthServerException::invalidRefreshToken(
|
||||
'Token is not linked to client,' .
|
||||
' got: ' . $clientId .
|
||||
' expected: ' . $refreshTokenData['client_id']
|
||||
);
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_CLIENT_FAILED, $request));
|
||||
throw OAuthServerException::invalidRefreshToken('Token is not linked to client');
|
||||
}
|
||||
|
||||
if ($refreshTokenData['expire_time'] < time()) {
|
||||
|
@@ -1,25 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Middleware;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthenticationServerMiddleware
|
||||
class AuthorizationServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Server
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* AuthenticationServerMiddleware constructor.
|
||||
* AuthorizationServerMiddleware constructor.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Server $server
|
||||
* @param \League\OAuth2\Server\AuthorizationServer $server
|
||||
*/
|
||||
public function __construct(Server $server)
|
||||
public function __construct(AuthorizationServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
@@ -39,9 +46,8 @@ class AuthenticationServerMiddleware
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
|
||||
->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
@@ -1,25 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Middleware;
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ResourceServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Server
|
||||
* @var \League\OAuth2\Server\ResourceServer
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* ResourceServerMiddleware constructor.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Server $server
|
||||
* @param \League\OAuth2\Server\ResourceServer $server
|
||||
*/
|
||||
public function __construct(Server $server)
|
||||
public function __construct(ResourceServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
@@ -39,9 +46,8 @@ class ResourceServerMiddleware
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
|
||||
->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Access token storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
@@ -18,11 +16,13 @@ interface ClientRepositoryInterface extends RepositoryInterface
|
||||
/**
|
||||
* Get a client.
|
||||
*
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
* @param string $grantType The grant type used
|
||||
* @param null|string $clientSecret The client's secret (if sent)
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
* @param string $grantType The grant type used
|
||||
* @param null|string $clientSecret The client's secret (if sent)
|
||||
* @param bool $mustValidateSecret If true the client must attempt to validate the secret unless the client
|
||||
* is confidential
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\ClientEntityInterface
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null);
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true);
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Repository interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
|
@@ -1,13 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Scope storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use League\Event\Event;
|
||||
@@ -7,6 +13,10 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class RequestEvent extends Event
|
||||
{
|
||||
const CLIENT_AUTHENTICATION_FAILED = 'client.authentication.failed';
|
||||
const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
|
||||
const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
|
||||
|
||||
/**
|
||||
* @var \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
|
@@ -1,4 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\RequestTypes;
|
||||
|
||||
@@ -57,6 +64,18 @@ class AuthorizationRequest
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The code challenge (if provided)
|
||||
* @var string
|
||||
*/
|
||||
protected $codeChallenge;
|
||||
|
||||
/**
|
||||
* The code challenge method (if provided)
|
||||
* @var string
|
||||
*/
|
||||
protected $codeChallengeMethod;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@@ -168,4 +187,36 @@ class AuthorizationRequest
|
||||
{
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCodeChallenge()
|
||||
{
|
||||
return $this->codeChallenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $codeChallenge
|
||||
*/
|
||||
public function setCodeChallenge($codeChallenge)
|
||||
{
|
||||
$this->codeChallenge = $codeChallenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCodeChallengeMethod()
|
||||
{
|
||||
return $this->codeChallengeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $codeChallengeMethod
|
||||
*/
|
||||
public function setCodeChallengeMethod($codeChallengeMethod)
|
||||
{
|
||||
$this->codeChallengeMethod = $codeChallengeMethod;
|
||||
}
|
||||
}
|
||||
|
80
src/ResourceServer.php
Normal file
80
src/ResourceServer.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface;
|
||||
use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ResourceServer
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
/**
|
||||
* @var \League\OAuth2\Server\CryptKey|string
|
||||
*/
|
||||
private $publicKey;
|
||||
/**
|
||||
* @var \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface|null
|
||||
*/
|
||||
private $authorizationValidator;
|
||||
|
||||
/**
|
||||
* New server instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param \League\OAuth2\Server\CryptKey|string $publicKey
|
||||
* @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator
|
||||
*/
|
||||
public function __construct(
|
||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||
$publicKey,
|
||||
AuthorizationValidatorInterface $authorizationValidator = null
|
||||
) {
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
|
||||
if (!$publicKey instanceof CryptKey) {
|
||||
$publicKey = new CryptKey($publicKey);
|
||||
}
|
||||
$this->publicKey = $publicKey;
|
||||
|
||||
$this->authorizationValidator = $authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface
|
||||
*/
|
||||
protected function getAuthorizationValidator()
|
||||
{
|
||||
if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) {
|
||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||
}
|
||||
|
||||
$this->authorizationValidator->setPublicKey($this->publicKey);
|
||||
|
||||
return $this->authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token validity.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthenticatedRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->getAuthorizationValidator()->validateAuthorization($request);
|
||||
}
|
||||
}
|
@@ -39,7 +39,7 @@ class BearerTokenResponse extends AbstractResponseType
|
||||
'access_token_id' => $this->accessToken->getIdentifier(),
|
||||
'scopes' => $this->accessToken->getScopes(),
|
||||
'user_id' => $this->accessToken->getUserIdentifier(),
|
||||
'expire_time' => $expireDateTime,
|
||||
'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace LeagueTests;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
@@ -13,7 +14,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
||||
use League\OAuth2\Server\Server;
|
||||
use LeagueTests\Stubs\AccessTokenEntity;
|
||||
use LeagueTests\Stubs\AuthCodeEntity;
|
||||
use LeagueTests\Stubs\ClientEntity;
|
||||
@@ -24,11 +24,11 @@ use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
|
||||
class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testRespondToRequestInvalidGrantType()
|
||||
{
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$this->getMock(ClientRepositoryInterface::class),
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
@@ -58,7 +58,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class);
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepositoryMock,
|
||||
$scopeRepositoryMock,
|
||||
@@ -80,7 +80,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
@@ -95,30 +95,11 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($method->invoke($server) instanceof BearerTokenResponse);
|
||||
}
|
||||
|
||||
public function testValidateAuthenticatedRequest()
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
'file://' . __DIR__ . '/Stubs/private.key',
|
||||
'file://' . __DIR__ . '/Stubs/public.key'
|
||||
);
|
||||
|
||||
try {
|
||||
$server->validateAuthenticatedRequest(ServerRequestFactory::fromGlobals());
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals('Missing "Authorization" header', $e->getHint());
|
||||
}
|
||||
}
|
||||
|
||||
public function testCompleteAuthorizationRequest()
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
@@ -164,7 +145,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepositoryMock,
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
@@ -196,7 +177,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testValidateAuthorizationRequestUnregistered()
|
||||
{
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$this->getMock(ClientRepositoryInterface::class),
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
@@ -32,6 +32,76 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$grantMock->setEmitter(new Emitter());
|
||||
}
|
||||
|
||||
public function testHttpBasicWithPassword()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:Sesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
$this->assertSame(['Open', 'Sesame'], $basicAuthMethod->invoke($grantMock, $serverRequest));
|
||||
}
|
||||
|
||||
public function testHttpBasicNoPassword()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
$this->assertSame(['Open', ''], $basicAuthMethod->invoke($grantMock, $serverRequest));
|
||||
}
|
||||
|
||||
public function testHttpBasicNotBasic()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Foo ' . base64_encode('Open:Sesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
|
||||
}
|
||||
|
||||
public function testHttpBasicNotBase64()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ||');
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
|
||||
}
|
||||
|
||||
public function testHttpBasicNoColon()
|
||||
{
|
||||
/** @var AbstractGrant $grantMock */
|
||||
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
|
||||
$abstractGrantReflection = new \ReflectionClass($grantMock);
|
||||
|
||||
$serverRequest = new ServerRequest();
|
||||
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('OpenSesame'));
|
||||
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
|
||||
$basicAuthMethod->setAccessible(true);
|
||||
|
||||
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
|
||||
}
|
||||
|
||||
public function testValidateClientPublic()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
@@ -275,7 +345,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
||||
/** @var RefreshTokenEntityInterface $refreshToken */
|
||||
$refreshToken = $issueRefreshTokenMethod->invoke($grantMock, $accessToken);
|
||||
$this->assertTrue($refreshToken instanceof RefreshTokenEntityInterface);
|
||||
$this->assertFalse($refreshToken->isExpired());
|
||||
$this->assertEquals($accessToken, $refreshToken->getAccessToken());
|
||||
}
|
||||
|
||||
@@ -301,7 +370,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
|
||||
[new ScopeEntity()]
|
||||
);
|
||||
$this->assertTrue($accessToken instanceof AccessTokenEntityInterface);
|
||||
$this->assertFalse($accessToken->isExpired());
|
||||
}
|
||||
|
||||
public function testIssueAuthCode()
|
||||
|
@@ -6,6 +6,7 @@ use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
@@ -27,7 +28,7 @@ use Zend\Diactoros\ServerRequest;
|
||||
class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* CryptTrait stub
|
||||
* @var CryptTraitStub
|
||||
*/
|
||||
protected $cryptStub;
|
||||
|
||||
@@ -136,6 +137,41 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
||||
}
|
||||
|
||||
|
||||
public function testValidateAuthorizationRequestCodeChallenge()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setRedirectUri('http://foo/bar');
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_challenge' => 'FOOBAR',
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
@@ -272,6 +308,82 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
*/
|
||||
public function testValidateAuthorizationRequestMissingCodeChallenge()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setRedirectUri('http://foo/bar');
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
]
|
||||
);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
*/
|
||||
public function testValidateAuthorizationRequestInvalidCodeChallengeMethod()
|
||||
{
|
||||
$client = new ClientEntity();
|
||||
$client->setRedirectUri('http://foo/bar');
|
||||
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
'php://input',
|
||||
$headers = [],
|
||||
$cookies = [],
|
||||
$queryParams = [
|
||||
'response_type' => 'code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_challenge' => 'foobar',
|
||||
'code_challenge_method' => 'foo',
|
||||
]
|
||||
);
|
||||
|
||||
$grant->validateAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
public function testCompleteAuthorizationRequest()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
@@ -390,6 +502,150 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
|
||||
public function testRespondToAccessTokenRequestCodeChallengePlain()
|
||||
{
|
||||
$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->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_verifier' => 'foobar',
|
||||
'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' => 'foobar',
|
||||
'code_challenge_method' => 'plain',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
/** @var StubResponseType $response */
|
||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
|
||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
|
||||
public function testRespondToAccessTokenRequestCodeChallengeS256()
|
||||
{
|
||||
$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->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_verifier' => 'foobar',
|
||||
'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' => urlencode(base64_encode(hash('sha256', 'foobar'))),
|
||||
'code_challenge_method' => 'S256',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
/** @var StubResponseType $response */
|
||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
|
||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 3
|
||||
@@ -710,4 +966,517 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($e->getHint(), 'Cannot decrypt the authorization code');
|
||||
}
|
||||
}
|
||||
|
||||
public function testRespondToAccessTokenRequestBadCodeVerifierPlain()
|
||||
{
|
||||
$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->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_verifier' => 'nope',
|
||||
'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' => 'foobar',
|
||||
'code_challenge_method' => 'plain',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
/* @var StubResponseType $response */
|
||||
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals($e->getHint(), 'Failed to verify `code_verifier`.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testRespondToAccessTokenRequestBadCodeVerifierS256()
|
||||
{
|
||||
$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->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'code_verifier' => 'nope',
|
||||
'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' => 'foobar',
|
||||
'code_challenge_method' => 'S256',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
/* @var StubResponseType $response */
|
||||
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals($e->getHint(), 'Failed to verify `code_verifier`.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testRespondToAccessTokenRequestMissingCodeVerifier()
|
||||
{
|
||||
$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->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->enableCodeExchangeProof();
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'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' => 'foobar',
|
||||
'code_challenge_method' => 'plain',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
/* @var StubResponseType $response */
|
||||
$grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals($e->getHint(), 'Check the `code_verifier` parameter');
|
||||
}
|
||||
}
|
||||
|
||||
public function testAuthCodeRepositoryUniqueConstraintCheck()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||
|
||||
$authCodeRepository->expects($this->at(0))->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
$authCodeRepository->expects($this->at(1))->method('persistNewAuthCode');
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 7
|
||||
*/
|
||||
public function testAuthCodeRepositoryFailToPersist()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||
$authCodeRepository->method('persistNewAuthCode')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||
* @expectedExceptionCode 100
|
||||
*/
|
||||
public function testAuthCodeRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||
$authCodeRepository->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||
}
|
||||
|
||||
public function testRefreshTokenRepositoryUniqueConstraintCheck()
|
||||
{
|
||||
$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('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||
$refreshTokenRepositoryMock->expects($this->at(0))->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
$refreshTokenRepositoryMock->expects($this->at(1))->method('persistNewRefreshToken');
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'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',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
/** @var StubResponseType $response */
|
||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
|
||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 7
|
||||
*/
|
||||
public function testRefreshTokenRepositoryFailToPersist()
|
||||
{
|
||||
$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('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'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',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
/** @var StubResponseType $response */
|
||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
|
||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||
* @expectedExceptionCode 100
|
||||
*/
|
||||
public function testRefreshTokenRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||
{
|
||||
$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('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
|
||||
$grant = new AuthCodeGrant(
|
||||
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||
new \DateInterval('PT10M')
|
||||
);
|
||||
$grant->setClientRepository($clientRepositoryMock);
|
||||
$grant->setScopeRepository($scopeRepositoryMock);
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
|
||||
$request = new ServerRequest(
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
'POST',
|
||||
'php://input',
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => 'foo',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
'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',
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
/** @var StubResponseType $response */
|
||||
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||
|
||||
$this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
namespace LeagueTests\Grant;
|
||||
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||
use League\OAuth2\Server\Grant\ImplicitGrant;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
@@ -295,4 +297,76 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
|
||||
public function testAccessTokenRepositoryUniqueConstraintCheck()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->expects($this->at(0))->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
$accessTokenRepositoryMock->expects($this->at(1))->method('persistNewAccessToken')->willReturnSelf();
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||
* @expectedExceptionCode 7
|
||||
*/
|
||||
public function testAccessTokenRepositoryFailToPersist()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||
* @expectedExceptionCode 100
|
||||
*/
|
||||
public function testAccessTokenRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||
{
|
||||
$authRequest = new AuthorizationRequest();
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
$authRequest->setClient(new ClientEntity());
|
||||
$authRequest->setGrantTypeId('authorization_code');
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||
|
||||
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||
|
||||
$grant->completeAuthorizationRequest($authRequest);
|
||||
}
|
||||
}
|
||||
|
@@ -2,20 +2,20 @@
|
||||
|
||||
namespace LeagueTests\Middleware;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\Server;
|
||||
use LeagueTests\Stubs\AccessTokenEntity;
|
||||
use LeagueTests\Stubs\ClientEntity;
|
||||
use LeagueTests\Stubs\StubResponseType;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
|
||||
class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testValidResponse()
|
||||
{
|
||||
@@ -28,7 +28,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$accessRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class);
|
||||
$accessRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessRepositoryMock,
|
||||
$scopeRepositoryMock,
|
||||
@@ -45,7 +45,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
|
||||
$middleware = new AuthenticationServerMiddleware($server);
|
||||
$middleware = new AuthorizationServerMiddleware($server);
|
||||
$response = $middleware->__invoke(
|
||||
$request,
|
||||
new Response(),
|
||||
@@ -61,7 +61,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
$clientRepository->method('getClientEntity')->willReturn(null);
|
||||
|
||||
$server = new Server(
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
@@ -78,7 +78,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
|
||||
$middleware = new AuthenticationServerMiddleware($server);
|
||||
$middleware = new AuthorizationServerMiddleware($server);
|
||||
|
||||
$response = $middleware->__invoke(
|
||||
$request,
|
@@ -5,12 +5,9 @@ namespace LeagueTests\Middleware;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\Server;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use LeagueTests\Stubs\AccessTokenEntity;
|
||||
use LeagueTests\Stubs\ClientEntity;
|
||||
use LeagueTests\Stubs\StubResponseType;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
|
||||
@@ -18,15 +15,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testValidResponse()
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$server = new ResourceServer(
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
'file://' . __DIR__ . '/../Stubs/private.key',
|
||||
'file://' . __DIR__ . '/../Stubs/public.key',
|
||||
new StubResponseType()
|
||||
'file://' . __DIR__ . '/../Stubs/public.key'
|
||||
);
|
||||
|
||||
$client = new ClientEntity();
|
||||
@@ -59,15 +50,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testValidResponseExpiredToken()
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$server = new ResourceServer(
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
'file://' . __DIR__ . '/../Stubs/private.key',
|
||||
'file://' . __DIR__ . '/../Stubs/public.key',
|
||||
new StubResponseType()
|
||||
'file://' . __DIR__ . '/../Stubs/public.key'
|
||||
);
|
||||
|
||||
$client = new ClientEntity();
|
||||
@@ -100,15 +85,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testErrorResponse()
|
||||
{
|
||||
$clientRepository = $this->getMock(ClientRepositoryInterface::class);
|
||||
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$server = new ResourceServer(
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
$this->getMock(ScopeRepositoryInterface::class),
|
||||
'file://' . __DIR__ . '/../Stubs/private.key',
|
||||
'file://' . __DIR__ . '/../Stubs/public.key',
|
||||
new StubResponseType()
|
||||
'file://' . __DIR__ . '/../Stubs/public.key'
|
||||
);
|
||||
|
||||
$request = new ServerRequest();
|
||||
|
26
tests/ResourceServerTest.php
Normal file
26
tests/ResourceServerTest.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace LeagueTests;
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
|
||||
class ResourceServerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testValidateAuthenticatedRequest()
|
||||
{
|
||||
$server = new ResourceServer(
|
||||
$this->getMock(AccessTokenRepositoryInterface::class),
|
||||
'file://' . __DIR__ . '/Stubs/public.key'
|
||||
);
|
||||
|
||||
try {
|
||||
$server->validateAuthenticatedRequest(ServerRequestFactory::fromGlobals());
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals('Missing "Authorization" header', $e->getHint());
|
||||
}
|
||||
}
|
||||
}
|
@@ -226,4 +226,31 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testDetermineMissingBearerInHeader()
|
||||
{
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
|
||||
$responseType = new BearerTokenResponse($accessTokenRepositoryMock);
|
||||
$responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||
|
||||
$authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock);
|
||||
$authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||
$authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||
|
||||
$request = new ServerRequest();
|
||||
$request = $request->withHeader('authorization', 'Bearer blah.blah.blah');
|
||||
|
||||
try {
|
||||
$authorizationValidator->validateAuthorization($request);
|
||||
} catch (OAuthServerException $e) {
|
||||
$this->assertEquals(
|
||||
'Error while decoding to JSON',
|
||||
$e->getHint()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user