mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9658aa80ba | ||
|
08b1640ea3 |
18
.gitattributes
vendored
18
.gitattributes
vendored
@@ -1,13 +1,5 @@
|
||||
* text=auto
|
||||
|
||||
/examples export-ignore
|
||||
/tests export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
.travis.yml export-ignore
|
||||
.scrutinizer.yml export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/CHANGELOG.md export-ignore
|
||||
/CONTRIBUTING.md export-ignore
|
||||
/README.md export-ignore
|
||||
tests/ export-ignore
|
||||
phpunit.xml export-ignore
|
||||
build.xml export-ignore
|
||||
test export-ignore
|
||||
.travis.yml export-ignore
|
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,8 +1,6 @@
|
||||
/vendor
|
||||
/composer.lock
|
||||
phpunit.xml
|
||||
.idea
|
||||
/examples/vendor
|
||||
examples/public.key
|
||||
examples/private.key
|
||||
build
|
||||
/tests/coverage
|
||||
/docs
|
||||
/testing
|
||||
build/coverage
|
@@ -1,35 +0,0 @@
|
||||
filter:
|
||||
excluded_paths:
|
||||
- tests/*
|
||||
- vendor/*
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
remove_extra_empty_lines: true
|
||||
remove_php_closing_tag: true
|
||||
remove_trailing_whitespace: true
|
||||
fix_use_statements:
|
||||
remove_unused: true
|
||||
preserve_multiple: false
|
||||
preserve_blanklines: true
|
||||
order_alphabetically: true
|
||||
fix_php_opening_tag: true
|
||||
fix_linefeed: true
|
||||
fix_line_ending: true
|
||||
fix_identation_4spaces: true
|
||||
fix_doc_comments: true
|
||||
tools:
|
||||
external_code_coverage:
|
||||
timeout: 1800
|
||||
php_code_coverage: false
|
||||
php_code_sniffer:
|
||||
config:
|
||||
standard: PSR2
|
||||
filter:
|
||||
paths: ['src']
|
||||
php_loc:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
php_cpd:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
53
.styleci.yml
53
.styleci.yml
@@ -1,53 +0,0 @@
|
||||
preset: psr2
|
||||
|
||||
enabled:
|
||||
- binary_operator_spaces
|
||||
- blank_line_before_return
|
||||
- concat_with_spaces
|
||||
- function_typehint_space
|
||||
- hash_to_slash_comment
|
||||
- include
|
||||
- lowercase_cast
|
||||
- method_separation
|
||||
- native_function_casing
|
||||
- no_blank_lines_after_class_opening
|
||||
- no_blank_lines_between_uses
|
||||
- no_duplicate_semicolons
|
||||
- no_leading_import_slash
|
||||
- no_leading_namespace_whitespace
|
||||
- no_multiline_whitespace_before_semicolons
|
||||
- no_php4_constructor
|
||||
- no_short_bool_cast
|
||||
- no_singleline_whitespace_before_semicolons
|
||||
- no_trailing_comma_in_singleline_array
|
||||
- no_unreachable_default_argument_value
|
||||
- no_unused_imports
|
||||
- no_whitespace_before_comma_in_array
|
||||
- ordered_imports
|
||||
- phpdoc_align
|
||||
- phpdoc_indent
|
||||
- phpdoc_inline_tag
|
||||
- phpdoc_no_access
|
||||
- phpdoc_no_simplified_null_return
|
||||
- phpdoc_order
|
||||
- phpdoc_property
|
||||
- phpdoc_scalar
|
||||
- phpdoc_separation
|
||||
- phpdoc_to_comment
|
||||
- phpdoc_trim
|
||||
- phpdoc_type_to_var
|
||||
- phpdoc_types
|
||||
- phpdoc_var_without_name
|
||||
- print_to_echo
|
||||
- short_array_syntax
|
||||
- short_scalar_cast
|
||||
- simplified_null_return
|
||||
- single_quote
|
||||
- spaces_cast
|
||||
- standardize_not_equal
|
||||
- ternary_operator_spaces
|
||||
- trailing_comma_in_multiline_array
|
||||
- trim_array_spaces
|
||||
- unary_operator_spaces
|
||||
- whitespace_after_comma_in_array
|
||||
- whitespacy_lines
|
32
.travis.yml
32
.travis.yml
@@ -1,24 +1,18 @@
|
||||
language: php
|
||||
|
||||
sudo: false
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
before_script: composer install --prefer-source
|
||||
script: phpunit --configuration phpunit.xml.dist
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
|
||||
php:
|
||||
- 5.5.9
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- vendor
|
||||
|
221
CHANGELOG.md
221
CHANGELOG.md
@@ -1,223 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 5.1.5 (released 2017-07-11)
|
||||
|
||||
To address feedback from the security release the following two changes have been made:
|
||||
|
||||
* If an RSA key cannot be `chmod`'ed to 600 then it will now throw a `E_USER_NOTICE` instead of an exception.
|
||||
* Not using the new encryption key method on `AuthorizationServer` will set throw an `E_USER_DEPRECATED` message instead of an error.
|
||||
|
||||
## 5.1.4 (released 2017-07-01)
|
||||
|
||||
* Fixed multiple security vulnerabilities as a result of a security audit paid for by the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source). All users of this library are encouraged to update as soon as possible to this version or version 6.0 or greater.
|
||||
* It is recommended on each `AuthorizationServer` instance you set the `setEncryptionKey()`. This will result in stronger encryption being used. If this method is not set messages will be sent to the defined error handling routines (using `error_log`). Please see the examples and documentation for examples.
|
||||
* TravisCI now tests PHP 7.1 (Issue #671)
|
||||
* Fix middleware example fatal error (Issue #682)
|
||||
* Fix typo in the first README sentence (Issue #690)
|
||||
* Corrected DateInterval from 1 min to 1 month (Issue #709)
|
||||
|
||||
## 5.1.3 (released 2016-10-12)
|
||||
|
||||
* Fixed WWW-Authenticate header (Issue #669)
|
||||
* Increase the recommended RSA key length from 1024 to 2048 bits (Issue #668)
|
||||
|
||||
## 5.1.2 (released 2016-09-19)
|
||||
|
||||
* Fixed `finalizeScopes` call (Issue #650)
|
||||
|
||||
## 5.1.1 (released 2016-07-26)
|
||||
|
||||
* Improved test suite (Issue #614)
|
||||
* Updated docblocks (Issue #616)
|
||||
* Replace `array_shift` with `foreach` loop (Issue #621)
|
||||
* Allow easy addition of custom fields to Bearer token response (Issue #624)
|
||||
* Key file auto-generation from string (Issue #625)
|
||||
|
||||
## 5.1.0 (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)
|
||||
* Handle RSA key passphrase (Issue #502)
|
||||
* Remove access token repository from response types (Issue #501)
|
||||
* Remove unnecessary methods from entity interfaces (Issue #490)
|
||||
* Ensure incoming JWT hasn't expired (Issue #509)
|
||||
* Fix client identifier passed where user identifier is expected (Issue #498)
|
||||
* Removed built-in entities; added traits to for quick re-use (Issue #504)
|
||||
* Redirect uri is required only if the "redirect_uri" parameter was included in the authorization request (Issue #514)
|
||||
* Removed templating for auth code and implicit grants (Issue #499)
|
||||
|
||||
## 5.0.0-RC1 (release 2016-03-24)
|
||||
|
||||
Version 5 is a complete code rewrite.
|
||||
|
||||
* 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
|
||||
|
||||
## 4.1.5 (released 2016-01-04)
|
||||
|
||||
* Enable Symfony 3.0 support (#412)
|
||||
|
||||
## 4.1.4 (released 2015-11-13)
|
||||
|
||||
* Fix for determining access token in header (Issue #328)
|
||||
* Refresh tokens are now returned for MAC responses (Issue #356)
|
||||
* Added integration list to readme (Issue #341)
|
||||
* Expose parameter passed to exceptions (Issue #345)
|
||||
* Removed duplicate routing setup code (Issue #346)
|
||||
* Docs fix (Issues #347, #360, #380)
|
||||
* Examples fix (Issues #348, #358)
|
||||
* Fix typo in docblock (Issue #352)
|
||||
* Improved timeouts for MAC tokens (Issue #364)
|
||||
* `hash_hmac()` should output raw binary data, not hexits (Issue #370)
|
||||
* Improved regex for matching all Base64 characters (Issue #371)
|
||||
* Fix incorrect signature parameter (Issue #372)
|
||||
* AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377)
|
||||
* Added priority argument to event listener (Issue #388)
|
||||
|
||||
## 4.1.3 (released 2015-03-22)
|
||||
|
||||
* Docblock, namespace and inconsistency fixes (Issue #303)
|
||||
* Docblock type fix (Issue #310)
|
||||
* Example bug fix (Issue #300)
|
||||
* Updated league/event to ~2.1 (Issue #311)
|
||||
* Fixed missing session scope (Issue #319)
|
||||
* Updated interface docs (Issue #323)
|
||||
* `.travis.yml` updates
|
||||
|
||||
## 4.1.2 (released 2015-01-01)
|
||||
|
||||
* Remove side-effects in hash_equals() implementation (Issue #290)
|
||||
|
||||
## 4.1.1 (released 2014-12-31)
|
||||
|
||||
* Changed `symfony/http-foundation` dependency version to `~2.4` so package can be installed in Laravel `4.1.*`
|
||||
|
||||
## 4.1.0 (released 2014-12-27)
|
||||
|
||||
* Added MAC token support (Issue #158)
|
||||
* Fixed example init code (Issue #280)
|
||||
* Toggle refresh token rotation (Issue #286)
|
||||
* Docblock fixes
|
||||
|
||||
## 4.0.5 (released 2014-12-15)
|
||||
|
||||
* Prevent duplicate session in auth code grant (Issue #282)
|
||||
|
||||
## 4.0.4 (released 2014-12-03)
|
||||
|
||||
* Ensure refresh token hasn't expired (Issue #270)
|
||||
|
||||
## 4.0.3 (released 2014-12-02)
|
||||
|
||||
* Fix bad type hintings (Issue #267)
|
||||
* Do not forget to set the expire time (Issue #268)
|
||||
|
||||
## 4.0.2 (released 2014-11-21)
|
||||
|
||||
* Improved interfaces (Issue #255)
|
||||
* Learnt how to spell delimiter and so `getScopeDelimiter()` and `setScopeDelimiter()` methods have been renamed
|
||||
* Docblock improvements (Issue #254)
|
||||
|
||||
## 4.0.1 (released 2014-11-09)
|
||||
|
||||
* Alias the master branch in composer.json (Issue #243)
|
||||
* Numerous PHP CodeSniffer fixes (Issue #244)
|
||||
* .travis.yml update (Issue #245)
|
||||
* The getAccessToken method should return an AccessTokenEntity object instead of a string in ResourceServer.php (#246)
|
||||
|
||||
## 4.0.0 (released 2014-11-08)
|
||||
|
||||
* Complete rewrite
|
||||
* Check out the documentation - [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com)
|
||||
|
||||
## 3.2.0 (released 2014-04-16)
|
||||
## 3.2 (released 2014-04-16)
|
||||
|
||||
* Added the ability to change the algorithm that is used to generate the token strings (Issue #151)
|
||||
|
||||
@@ -299,7 +82,7 @@ Version 5 is a complete code rewrite.
|
||||
* Included a PDO driver which implements the storage interfaces so the library is more "get up and go"
|
||||
* Further normalised the database structure so all sessions no longer contain infomation related to authorization grant (which may or may not be enabled)
|
||||
* A session can have multiple associated access tokens
|
||||
* Individual grants can have custom expire times for access tokens
|
||||
* Induvidual grants can have custom expire times for access tokens
|
||||
* Authorization codes now have a TTL of 10 minutes by default (can be manually set)
|
||||
* Refresh tokens now have a TTL of one week by default (can be manually set)
|
||||
* The client credentials grant will no longer gives out refresh tokens as per the specification
|
||||
|
22
CONDUCT.md
22
CONDUCT.md
@@ -1,22 +0,0 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) Alex Bilbie
|
||||
Copyright (C) 2013 PHP League of Extraordinary Packages
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
107
README.md
107
README.md
@@ -1,53 +1,68 @@
|
||||
# PHP OAuth 2.0 Server
|
||||
|
||||
### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning:
|
||||
### Security Notice
|
||||
[](https://packagist.org/packages/league/oauth2-server) [](https://coveralls.io/r/thephpleague/oauth2-server?branch=master) [](https://packagist.org/packages/league/oauth2-server) [](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
### Please upgrade to version `>=5.1.4` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities
|
||||
### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning:
|
||||
|
||||
[](https://github.com/thephpleague/oauth2-server/releases)
|
||||
[](LICENSE.md)
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server)
|
||||
[](https://packagist.org/packages/league/oauth2-server)
|
||||
A standards compliant [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authorization server and resource server written in PHP.
|
||||
|
||||
`league/oauth2-server` is a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
||||
## Package Installation
|
||||
|
||||
It supports out of the box the following grants:
|
||||
The framework is provided as a Composer package which can be installed by adding the package to your `composer.json` file:
|
||||
|
||||
* Authorization code grant
|
||||
* Implicit grant
|
||||
* Client credentials grant
|
||||
* Resource owner password credentials grant
|
||||
* Refresh grant
|
||||
```javascript
|
||||
{
|
||||
"require": {
|
||||
"league/oauth2-server": "~3.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following RFCs are implemented:
|
||||
### Framework Integrations
|
||||
|
||||
* [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)
|
||||
* [Laravel Service Provider](https://packagist.org/packages/lucadegasperi/oauth2-server-laravel) by @lucadegasperi
|
||||
* [Laravel Eloquent implementation](https://github.com/ScubaClick/scubaclick-oauth2) by @ScubaClick (under development)
|
||||
|
||||
This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](https://twitter.com/alexbilbie).
|
||||
---
|
||||
|
||||
## Requirements
|
||||
The library features 100% unit test code coverage. To run the tests yourself run `phpunit` from the project root.
|
||||
|
||||
The following versions of PHP are supported:
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server) [master]
|
||||
|
||||
* PHP 5.5 (>=5.5.9)
|
||||
* PHP 5.6
|
||||
* PHP 7.0
|
||||
* PHP 7.1
|
||||
* HHVM
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server) [develop]
|
||||
|
||||
The `openssl` extension is also required.
|
||||
|
||||
## Documentation
|
||||
## Current Features
|
||||
|
||||
The library documentation can be found at [https://oauth2.thephpleague.com](https://oauth2.thephpleague.com).
|
||||
You can contribute to the documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/).
|
||||
### Authorization Server
|
||||
|
||||
The authorization server is a flexible class and the following core specification grants are implemented:
|
||||
|
||||
* authorization code ([section 4.1](http://tools.ietf.org/html/rfc6749#section-4.1))
|
||||
* refresh token ([section 6](http://tools.ietf.org/html/rfc6749#section-6))
|
||||
* client credentials ([section 2.3.1](http://tools.ietf.org/html/rfc6749#section-2.3.1))
|
||||
* password (user credentials) ([section 4.3](http://tools.ietf.org/html/rfc6749#section-4.3))
|
||||
|
||||
An [overview of the different OAuth 2.0 grants](https://github.com/thephpleague/oauth2-server/wiki/Which-OAuth-2.0-grant-should-I-use%3F) can be found in the [wiki].
|
||||
|
||||
### Resource Server
|
||||
|
||||
The resource server allows you to secure your API endpoints by checking for a valid OAuth access token in the request and ensuring the token has the correct scope(s) (i.e. permissions) to access resources.
|
||||
|
||||
### Custom grants
|
||||
|
||||
Custom grants can be created easily by implementing an interface. Check out the [custom grant guide](https://github.com/thephpleague/oauth2-server/wiki/Creating-custom-grants).
|
||||
|
||||
## Tutorials and Documentation
|
||||
|
||||
* **[Wiki]** - The wiki has lots of guides on how to use this library.
|
||||
|
||||
* **[Developing an OAuth-2.0 Authorization Server]** - A simple tutorial on how to use the authorization server.
|
||||
|
||||
* **[Securing your API with OAuth 2.0]** - A simple tutorial on how to use the resource server to secure an API server.
|
||||
|
||||
[Wiki]: https://github.com/thephpleague/oauth2-server/wiki
|
||||
[Securing your API with OAuth 2.0]: https://github.com/thephpleague/oauth2-server/wiki/Securing-your-API-with-OAuth-2.0
|
||||
[Developing an OAuth-2.0 Authorization Server]: https://github.com/thephpleague/oauth2-server/wiki/Developing-an-OAuth-2.0-authorization-server
|
||||
|
||||
## Changelog
|
||||
|
||||
@@ -55,21 +70,11 @@ You can contribute to the documentation in the [gh-pages branch](https://github.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details.
|
||||
Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) for details.
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues).
|
||||
|
||||
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.
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues)
|
||||
|
||||
## License
|
||||
|
||||
@@ -79,8 +84,14 @@ This package is released under the MIT License. See the bundled [LICENSE](https:
|
||||
|
||||
This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie).
|
||||
|
||||
Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors).
|
||||
Special thanks to:
|
||||
|
||||
Additional thanks go to the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source) for funding a security audit of this library.
|
||||
* [Dan Horrigan](https://github.com/dandoescode)
|
||||
* [Nick Jackson](https://github.com/jacksonj04)
|
||||
* [Michael Gooden](https://github.com/MichaelGooden)
|
||||
* [Phil Sturgeon](https://github.com/philsturgeon)
|
||||
* [and all the other contributors](https://github.com/thephpleague/oauth2-server/contributors)
|
||||
|
||||
The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme.
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
117
composer.json
117
composer.json
@@ -1,72 +1,49 @@
|
||||
{
|
||||
"name": "league/oauth2-server",
|
||||
"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": "https://oauth2.thephpleague.com/",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"ext-openssl": "*",
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^2.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"defuse/php-encryption": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8 || ^5.0",
|
||||
"zendframework/zend-diactoros": "^1.0",
|
||||
"indigophp/hash-compat": "^1.1"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/oauth2-server.git"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"oauth 2",
|
||||
"oauth 2.0",
|
||||
"server",
|
||||
"auth",
|
||||
"authorization",
|
||||
"authorisation",
|
||||
"authentication",
|
||||
"resource",
|
||||
"api",
|
||||
"auth",
|
||||
"protect",
|
||||
"secure"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "hello@alexbilbie.com",
|
||||
"homepage": "http://www.alexbilbie.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"replace": {
|
||||
"lncd/oauth2": "*",
|
||||
"league/oauth2server": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"indigophp/hash-compat": "Polyfill for hash_equals function for PHP 5.5"
|
||||
}
|
||||
"name": "league/oauth2-server",
|
||||
"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.",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": ">=0.7.2",
|
||||
"league/phpunit-coverage-listener": "~1.0"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/oauth2-server.git"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"server",
|
||||
"authorization",
|
||||
"authentication",
|
||||
"resource",
|
||||
"api",
|
||||
"auth",
|
||||
"protect",
|
||||
"secure"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "hello@alexbilbie.com",
|
||||
"homepage": "http://www.alexbilbie.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"replace": {
|
||||
"lncd/oauth2": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"League\\OAuth2\\Server": "src/"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,53 +0,0 @@
|
||||
# Example implementations
|
||||
|
||||
## Installation
|
||||
|
||||
0. Run `composer install` in this directory to install dependencies
|
||||
0. Create a private key `openssl genrsa -out private.key 2048`
|
||||
0. Create a public key `openssl rsa -in private.key -pubout > public.key`
|
||||
0. `cd` into the public directory
|
||||
0. Start a PHP server `php -S localhost:4444`
|
||||
|
||||
## Testing the client credentials grant example
|
||||
|
||||
Send the following cURL request:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/client_credentials.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=client_credentials" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "scope=basic email"
|
||||
```
|
||||
|
||||
## Testing the password grant example
|
||||
|
||||
Send the following cURL request:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/password.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=password" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "username=alex" \
|
||||
--data-urlencode "password=whisky" \
|
||||
--data-urlencode "scope=basic email"
|
||||
```
|
||||
|
||||
## Testing the refresh token grant example
|
||||
|
||||
Send the following cURL request. Replace `{{REFRESH_TOKEN}}` with a refresh token from another grant above:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/refresh_token.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=refresh_token" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "refresh_token={{REFRESH_TOKEN}}"
|
||||
```
|
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"require": {
|
||||
"slim/slim": "3.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^2.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"defuse/php-encryption": "^2.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OAuth2ServerExamples\\": "src/",
|
||||
"League\\OAuth2\\Server\\": "../src/"
|
||||
}
|
||||
}
|
||||
}
|
523
examples/composer.lock
generated
523
examples/composer.lock
generated
@@ -1,523 +0,0 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "9813ed7c3b6dcf107f44df9392935b8f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/container-interop/container-interop.git",
|
||||
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8",
|
||||
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Interop\\Container\\": "src/Interop/Container/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||
"homepage": "https://github.com/container-interop/container-interop",
|
||||
"time": "2017-02-14T19:40:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/FastRoute.git",
|
||||
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FastRoute\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Popov",
|
||||
"email": "nikic@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Fast request router for PHP",
|
||||
"keywords": [
|
||||
"router",
|
||||
"routing"
|
||||
],
|
||||
"time": "2015-06-18T19:15:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/silexphp/Pimple.git",
|
||||
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
|
||||
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Pimple": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Pimple, a simple Dependency Injection Container",
|
||||
"homepage": "http://pimple.sensiolabs.org",
|
||||
"keywords": [
|
||||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2015-09-11T15:10:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||
"homepage": "https://github.com/php-fig/container",
|
||||
"keywords": [
|
||||
"PSR-11",
|
||||
"container",
|
||||
"container-interface",
|
||||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"time": "2017-02-14T16:28:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/3b06f0f2d84dabbe81b6cea46ace46a3e883253e",
|
||||
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"container-interop/container-interop": "^1.1",
|
||||
"nikic/fast-route": "^0.6",
|
||||
"php": ">=5.5.0",
|
||||
"pimple/pimple": "^3.0",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Slim\\": "Slim"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rob Allen",
|
||||
"email": "rob@akrabat.com",
|
||||
"homepage": "http://akrabat.com"
|
||||
},
|
||||
{
|
||||
"name": "Josh Lockhart",
|
||||
"email": "hello@joshlockhart.com",
|
||||
"homepage": "https://joshlockhart.com"
|
||||
},
|
||||
{
|
||||
"name": "Gabriel Manricks",
|
||||
"email": "gmanricks@me.com",
|
||||
"homepage": "http://gabrielmanricks.com"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Smith",
|
||||
"email": "a.smith@silentworks.co.uk",
|
||||
"homepage": "http://silentworks.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
|
||||
"homepage": "http://slimframework.com",
|
||||
"keywords": [
|
||||
"api",
|
||||
"framework",
|
||||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2015-12-07T14:11:09+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "defuse/php-encryption",
|
||||
"version": "v2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/defuse/php-encryption.git",
|
||||
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
|
||||
"reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"paragonie/random_compat": "~2.0",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^2.0|^3.0",
|
||||
"phpunit/phpunit": "^4|^5"
|
||||
},
|
||||
"bin": [
|
||||
"bin/generate-defuse-key"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Defuse\\Crypto\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Hornby",
|
||||
"email": "taylor@defuse.ca",
|
||||
"homepage": "https://defuse.ca/"
|
||||
},
|
||||
{
|
||||
"name": "Scott Arciszewski",
|
||||
"email": "info@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "Secure PHP Encryption Library",
|
||||
"keywords": [
|
||||
"aes",
|
||||
"authenticated encryption",
|
||||
"cipher",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encrypt",
|
||||
"encryption",
|
||||
"openssl",
|
||||
"security",
|
||||
"symmetric key cryptography"
|
||||
],
|
||||
"time": "2017-05-18T21:28:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/ddce703826f9c5229781933b1a39069e38e6a0f3",
|
||||
"reference": "ddce703826f9c5229781933b1a39069e38e6a0f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"mdanter/ecc": "~0.3.1",
|
||||
"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-10-31T20:09:32+00:00"
|
||||
},
|
||||
{
|
||||
"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-21T12:24:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||
"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": "2017-03-13T16:27:32+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
// 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(ResourceServer::class)
|
||||
)
|
||||
);
|
||||
|
||||
// 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',
|
||||
],
|
||||
];
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
);
|
||||
|
||||
$app->run();
|
@@ -1,109 +0,0 @@
|
||||
<?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 OAuth2ServerExamples\Entities\UserEntity;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
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,
|
||||
],
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
// Validate the HTTP request and return an AuthorizationRequest object.
|
||||
// The auth request object can be serialized into a user's session
|
||||
$authRequest = $server->validateAuthorizationRequest($request);
|
||||
|
||||
// Once the user has logged in set the user on the AuthorizationRequest
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
// Once the user has approved or denied the client update the status
|
||||
// (true = approved, false = denied)
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
|
||||
// Return the HTTP redirect response
|
||||
return $server->completeAuthorizationRequest($authRequest, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
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());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
@@ -1,80 +0,0 @@
|
||||
<?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 OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
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,
|
||||
],
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository(); // instance of ClientRepositoryInterface
|
||||
$scopeRepository = new ScopeRepository(); // instance of ScopeRepositoryInterface
|
||||
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface
|
||||
|
||||
// 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 AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKey,
|
||||
$publicKey
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
// Enable the client credentials grant on the server
|
||||
$server->enableGrantType(
|
||||
new \League\OAuth2\Server\Grant\ClientCredentialsGrant(),
|
||||
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\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());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
@@ -1,82 +0,0 @@
|
||||
<?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 OAuth2ServerExamples\Entities\UserEntity;
|
||||
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;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
// Enable the implicit grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H')));
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
// Validate the HTTP request and return an AuthorizationRequest object.
|
||||
// The auth request object can be serialized into a user's session
|
||||
$authRequest = $server->validateAuthorizationRequest($request);
|
||||
|
||||
// Once the user has logged in set the user on the AuthorizationRequest
|
||||
$authRequest->setUser(new UserEntity());
|
||||
|
||||
// Once the user has approved or denied the client update the status
|
||||
// (true = approved, false = denied)
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
|
||||
// Return the HTTP redirect response
|
||||
return $server->completeAuthorizationRequest($authRequest, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
@@ -1,111 +0,0 @@
|
||||
<?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\AuthorizationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
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,
|
||||
],
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
// Enable the refresh token grant on the server with a token TTL of 1 month
|
||||
$server->enableGrantType(
|
||||
new RefreshTokenGrant($refreshTokenRepository),
|
||||
new \DateInterval('P1M')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
ResourceServer::class => function () {
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
$server = new ResourceServer(
|
||||
new AccessTokenRepository(),
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
// Access token issuer
|
||||
$app->post('/access_token', function () {
|
||||
})->add(new AuthorizationServerMiddleware($app->getContainer()->get(AuthorizationServer::class)));
|
||||
|
||||
// Secured API
|
||||
$app->group('/api', function () {
|
||||
$this->get('/user', function (ServerRequestInterface $request, ResponseInterface $response) {
|
||||
$params = [];
|
||||
|
||||
if (in_array('basic', $request->getAttribute('oauth_scopes', []))) {
|
||||
$params = [
|
||||
'id' => 1,
|
||||
'name' => 'Alex',
|
||||
'city' => 'London',
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array('email', $request->getAttribute('oauth_scopes', []))) {
|
||||
$params['email'] = 'alex@example.com';
|
||||
}
|
||||
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write(json_encode($params));
|
||||
|
||||
return $response->withBody($body);
|
||||
});
|
||||
})->add(new ResourceServerMiddleware($app->getContainer()->get(ResourceServer::class)));
|
||||
|
||||
$app->run();
|
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
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;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
// Add the authorization server to the DI container
|
||||
AuthorizationServer::class => function () {
|
||||
|
||||
// Setup the authorization server
|
||||
$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
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
$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(
|
||||
$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\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
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,75 +0,0 @@
|
||||
<?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 OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
AuthorizationServer::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new AuthorizationServer(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
$server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen');
|
||||
|
||||
// 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(
|
||||
$grant,
|
||||
new \DateInterval('PT1H') // The new access token will expire after 1 hour
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\AuthorizationServer $server */
|
||||
$server = $app->getContainer()->get(AuthorizationServer::class);
|
||||
|
||||
try {
|
||||
return $server->respondToAccessTokenRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
@@ -1,20 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AccessTokenEntity implements AccessTokenEntityInterface
|
||||
{
|
||||
use AccessTokenTrait, TokenEntityTrait, EntityTrait;
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AuthCodeEntity implements AuthCodeEntityInterface
|
||||
{
|
||||
use EntityTrait, TokenEntityTrait, AuthCodeTrait;
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\ClientTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class ClientEntity implements ClientEntityInterface
|
||||
{
|
||||
use EntityTrait, ClientTrait;
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function setRedirectUri($uri)
|
||||
{
|
||||
$this->redirectUri = $uri;
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||
|
||||
class RefreshTokenEntity implements RefreshTokenEntityInterface
|
||||
{
|
||||
use RefreshTokenTrait, EntityTrait;
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class ScopeEntity implements ScopeEntityInterface
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getIdentifier();
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
|
||||
class UserEntity implements UserEntityInterface
|
||||
{
|
||||
/**
|
||||
* Return the user's identifier.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
<?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\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\AccessTokenEntity;
|
||||
|
||||
class AccessTokenRepository implements AccessTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
|
||||
{
|
||||
// Some logic here to save the access token to a database
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeAccessToken($tokenId)
|
||||
{
|
||||
// Some logic here to revoke the access token
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId)
|
||||
{
|
||||
return false; // Access token hasn't been revoked
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
|
||||
{
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setClient($clientEntity);
|
||||
foreach ($scopes as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
<?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\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\AuthCodeEntity;
|
||||
|
||||
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
||||
{
|
||||
// Some logic to persist the auth code to a database
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeAuthCode($codeId)
|
||||
{
|
||||
// Some logic to revoke the auth code in a database
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId)
|
||||
{
|
||||
return false; // The auth code has not been revoked
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewAuthCode()
|
||||
{
|
||||
return new AuthCodeEntity();
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
<?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\Repositories\ClientRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ClientEntity;
|
||||
|
||||
class ClientRepository implements ClientRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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',
|
||||
'is_confidential' => true,
|
||||
],
|
||||
];
|
||||
|
||||
// Check if client is registered
|
||||
if (array_key_exists($clientIdentifier, $clients) === false) {
|
||||
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']);
|
||||
$client->setRedirectUri($clients[$clientIdentifier]['redirect_uri']);
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
<?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\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\RefreshTokenEntity;
|
||||
|
||||
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface)
|
||||
{
|
||||
// Some logic to persist the refresh token in a database
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId)
|
||||
{
|
||||
// Some logic to revoke the refresh token in a database
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId)
|
||||
{
|
||||
return false; // The refresh token has not been revoked
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewRefreshToken()
|
||||
{
|
||||
return new RefreshTokenEntity();
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
<?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\ScopeRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ScopeEntity;
|
||||
|
||||
class ScopeRepository implements ScopeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($scopeIdentifier)
|
||||
{
|
||||
$scopes = [
|
||||
'basic' => [
|
||||
'description' => 'Basic details about you',
|
||||
],
|
||||
'email' => [
|
||||
'description' => 'Your email address',
|
||||
],
|
||||
];
|
||||
|
||||
if (array_key_exists($scopeIdentifier, $scopes) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope = new ScopeEntity();
|
||||
$scope->setIdentifier($scopeIdentifier);
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes,
|
||||
$grantType,
|
||||
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,33 +0,0 @@
|
||||
<?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\UserEntity;
|
||||
|
||||
class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity
|
||||
) {
|
||||
if ($username === 'alex' && $password === 'whisky') {
|
||||
return new UserEntity();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
@@ -1,24 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="true"
|
||||
stopOnFailure="true" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/Bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite name="Tests">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src</directory>
|
||||
<exclude>
|
||||
<directory suffix=".php">src/ResponseTypes/DefaultTemplates</directory>
|
||||
<directory suffix=".php">src/TemplateRenderer</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-text" target="php://stdout" title="thephpleague/oauth2-server" charset="UTF-8" yui="true"
|
||||
highlight="true" lowUpperBound="60" highLowerBound="90"/>
|
||||
<log type="coverage-html" target="build/coverage" title="thephpleague/oauth2-server" charset="UTF-8" yui="true"
|
||||
highlight="true" lowUpperBound="60" highLowerBound="90"/>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/Bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite name="Authorization Server">
|
||||
<directory suffix="Test.php">tests/authorization</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Resource Server">
|
||||
<directory suffix="Test.php">tests/resource</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Utility Methods">
|
||||
<directory suffix="Test.php">tests/util</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory suffix=".php">PEAR_INSTALL_DIR</directory>
|
||||
<directory suffix=".php">PHP_LIBDIR</directory>
|
||||
<directory suffix=".php">vendor</directory>
|
||||
<directory suffix=".php">tests</directory>
|
||||
<directory suffix=".php">testing</directory>
|
||||
</blacklist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-clover" target="/tmp/coverage.xml"/>
|
||||
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
|
||||
</logging>
|
||||
<listeners>
|
||||
<listener class="League\PHPUnitCoverageListener\Listener">
|
||||
<arguments>
|
||||
<array>
|
||||
<element key="printer">
|
||||
<object class="League\PHPUnitCoverageListener\Printer\StdOut"/>
|
||||
</element>
|
||||
<element key="hook">
|
||||
<object class="League\PHPUnitCoverageListener\Hook\Travis"/>
|
||||
</element>
|
||||
<element key="namespace">
|
||||
<string>League\OAuth2\Server</string>
|
||||
</element>
|
||||
<element key="repo_token">
|
||||
<string>DtNuuOrBh1QBXVyRqmVldC2Au11DVti9n</string>
|
||||
</element>
|
||||
<element key="target_url">
|
||||
<string>https://coveralls.io/api/v1/jobs</string>
|
||||
</element>
|
||||
<element key="coverage_dir">
|
||||
<string>/tmp</string>
|
||||
</element>
|
||||
</array>
|
||||
</arguments>
|
||||
</listener>
|
||||
</listeners>
|
||||
</phpunit>
|
||||
|
0
sql/index.html
Normal file
0
sql/index.html
Normal file
95
sql/mysql.sql
Normal file
95
sql/mysql.sql
Normal file
@@ -0,0 +1,95 @@
|
||||
CREATE TABLE `oauth_clients` (
|
||||
`id` CHAR(40) NOT NULL,
|
||||
`secret` CHAR(40) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`auto_approve` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oacl_clse_clid` (`secret`,`id`)
|
||||
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_client_endpoints` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` char(40) NOT NULL,
|
||||
`redirect_uri` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `i_oaclen_clid` (`client_id`),
|
||||
CONSTRAINT `f_oaclen_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_sessions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` char(40) NOT NULL,
|
||||
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
|
||||
`owner_id` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `i_uase_clid_owty_owid` (`client_id`,`owner_type`,`owner_id`),
|
||||
CONSTRAINT `f_oase_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_access_tokens` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`access_token` char(40) NOT NULL,
|
||||
`access_token_expires` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oaseacto_acto_seid` (`access_token`,`session_id`),
|
||||
KEY `f_oaseto_seid` (`session_id`),
|
||||
CONSTRAINT `f_oaseto_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_authcodes` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`auth_code` char(40) NOT NULL,
|
||||
`auth_code_expires` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `session_id` (`session_id`),
|
||||
CONSTRAINT `oauth_session_authcodes_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_redirects` (
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`redirect_uri` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`session_id`),
|
||||
CONSTRAINT `f_oasere_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_refresh_tokens` (
|
||||
`session_access_token_id` int(10) unsigned NOT NULL,
|
||||
`refresh_token` char(40) NOT NULL,
|
||||
`refresh_token_expires` int(10) unsigned NOT NULL,
|
||||
`client_id` char(40) NOT NULL,
|
||||
PRIMARY KEY (`session_access_token_id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
CONSTRAINT `oauth_session_refresh_tokens_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `f_oasetore_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_scopes` (
|
||||
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oasc_sc` (`scope`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_token_scopes` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_access_token_id` int(10) unsigned DEFAULT NULL,
|
||||
`scope_id` smallint(5) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_setosc_setoid_scid` (`session_access_token_id`,`scope_id`),
|
||||
KEY `f_oasetosc_scid` (`scope_id`),
|
||||
CONSTRAINT `f_oasetosc_scid` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
|
||||
CONSTRAINT `f_oasetosc_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_authcode_scopes` (
|
||||
`oauth_session_authcode_id` int(10) unsigned NOT NULL,
|
||||
`scope_id` smallint(5) unsigned NOT NULL,
|
||||
KEY `oauth_session_authcode_id` (`oauth_session_authcode_id`),
|
||||
KEY `scope_id` (`scope_id`),
|
||||
CONSTRAINT `oauth_session_authcode_scopes_ibfk_2` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `oauth_session_authcode_scopes_ibfk_1` FOREIGN KEY (`oauth_session_authcode_id`) REFERENCES `oauth_session_authcodes` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
@@ -1,237 +0,0 @@
|
||||
<?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\EmitterAwareInterface;
|
||||
use League\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthorizationServer implements EmitterAwareInterface
|
||||
{
|
||||
use EmitterAwareTrait;
|
||||
|
||||
const ENCRYPTION_KEY_ERROR = 'You must set the encryption key going forward to improve the security of this library - see this page for more information https://oauth2.thephpleague.com/v5-security-improvements/';
|
||||
|
||||
/**
|
||||
* @var GrantTypeInterface[]
|
||||
*/
|
||||
protected $enabledGrantTypes = [];
|
||||
|
||||
/**
|
||||
* @var \DateInterval[]
|
||||
*/
|
||||
protected $grantTypeAccessTokenTTL = [];
|
||||
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
protected $privateKey;
|
||||
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
protected $publicKey;
|
||||
|
||||
/**
|
||||
* @var null|ResponseTypeInterface
|
||||
*/
|
||||
protected $responseType;
|
||||
|
||||
/**
|
||||
* @var ClientRepositoryInterface
|
||||
*/
|
||||
private $clientRepository;
|
||||
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var ScopeRepositoryInterface
|
||||
*/
|
||||
private $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $encryptionKey;
|
||||
|
||||
/**
|
||||
* New server instance.
|
||||
*
|
||||
* @param ClientRepositoryInterface $clientRepository
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param ScopeRepositoryInterface $scopeRepository
|
||||
* @param CryptKey|string $privateKey
|
||||
* @param CryptKey|string $publicKey
|
||||
* @param null|ResponseTypeInterface $responseType
|
||||
*/
|
||||
public function __construct(
|
||||
ClientRepositoryInterface $clientRepository,
|
||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
$privateKey,
|
||||
$publicKey,
|
||||
ResponseTypeInterface $responseType = null
|
||||
) {
|
||||
$this->clientRepository = $clientRepository;
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
|
||||
if ($privateKey instanceof CryptKey === false) {
|
||||
$privateKey = new CryptKey($privateKey);
|
||||
}
|
||||
$this->privateKey = $privateKey;
|
||||
|
||||
if ($publicKey instanceof CryptKey === false) {
|
||||
$publicKey = new CryptKey($publicKey);
|
||||
}
|
||||
$this->publicKey = $publicKey;
|
||||
|
||||
$this->responseType = $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encryption key
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function setEncryptionKey($key)
|
||||
{
|
||||
$this->encryptionKey = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a grant type on the server.
|
||||
*
|
||||
* @param GrantTypeInterface $grantType
|
||||
* @param null|\DateInterval $accessTokenTTL
|
||||
*/
|
||||
public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL = null)
|
||||
{
|
||||
if ($accessTokenTTL instanceof \DateInterval === false) {
|
||||
$accessTokenTTL = new \DateInterval('PT1H');
|
||||
}
|
||||
|
||||
$grantType->setAccessTokenRepository($this->accessTokenRepository);
|
||||
$grantType->setClientRepository($this->clientRepository);
|
||||
$grantType->setScopeRepository($this->scopeRepository);
|
||||
$grantType->setPrivateKey($this->privateKey);
|
||||
$grantType->setPublicKey($this->publicKey);
|
||||
$grantType->setEmitter($this->getEmitter());
|
||||
|
||||
if ($this->encryptionKey === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
trigger_error(self::ENCRYPTION_KEY_ERROR, E_USER_DEPRECATED);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$grantType->setEncryptionKey($this->encryptionKey);
|
||||
|
||||
$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
|
||||
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an authorization request
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return AuthorizationRequest
|
||||
*/
|
||||
public function validateAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
if ($this->encryptionKey === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
trigger_error(self::ENCRYPTION_KEY_ERROR, E_USER_DEPRECATED);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
foreach ($this->enabledGrantTypes as $grantType) {
|
||||
if ($grantType->canRespondToAuthorizationRequest($request)) {
|
||||
return $grantType->validateAuthorizationRequest($request);
|
||||
}
|
||||
}
|
||||
|
||||
throw OAuthServerException::unsupportedGrantType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete an authorization request
|
||||
*
|
||||
* @param AuthorizationRequest $authRequest
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response)
|
||||
{
|
||||
return $this->enabledGrantTypes[$authRequest->getGrantTypeId()]
|
||||
->completeAuthorizationRequest($authRequest)
|
||||
->generateHttpResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an access token response.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
foreach ($this->enabledGrantTypes as $grantType) {
|
||||
if ($grantType->canRespondToAccessTokenRequest($request)) {
|
||||
$tokenResponse = $grantType->respondToAccessTokenRequest(
|
||||
$request,
|
||||
$this->getResponseType(),
|
||||
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
|
||||
);
|
||||
|
||||
if ($tokenResponse instanceof ResponseTypeInterface) {
|
||||
return $tokenResponse->generateHttpResponse($response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw OAuthServerException::unsupportedGrantType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token type that grants will return in the HTTP response.
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
protected function getResponseType()
|
||||
{
|
||||
if ($this->responseType instanceof ResponseTypeInterface === false) {
|
||||
$this->responseType = new BearerTokenResponse();
|
||||
}
|
||||
|
||||
$this->responseType->setPrivateKey($this->privateKey);
|
||||
$this->responseType->setEncryptionKey($this->encryptionKey);
|
||||
|
||||
return $this->responseType;
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
interface AuthorizationValidatorInterface
|
||||
{
|
||||
/**
|
||||
* Determine the access token in the authorization header and append OAUth properties to the request
|
||||
* as attributes.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthorization(ServerRequestInterface $request);
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use Lcobucci\JWT\Parser;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
use Lcobucci\JWT\ValidationData;
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class BearerTokenValidator implements AuthorizationValidatorInterface
|
||||
{
|
||||
use CryptTrait;
|
||||
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function __construct(AccessTokenRepositoryInterface $accessTokenRepository)
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorization(ServerRequestInterface $request)
|
||||
{
|
||||
if ($request->hasHeader('authorization') === false) {
|
||||
throw OAuthServerException::accessDenied('Missing "Authorization" header');
|
||||
}
|
||||
|
||||
$header = $request->getHeader('authorization');
|
||||
$jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0]));
|
||||
|
||||
try {
|
||||
// Attempt to parse and validate the JWT
|
||||
$token = (new Parser())->parse($jwt);
|
||||
if ($token->verify(new Sha256(), $this->publicKey->getKeyPath()) === false) {
|
||||
throw OAuthServerException::accessDenied('Access token could not be verified');
|
||||
}
|
||||
|
||||
// Ensure access token hasn't expired
|
||||
$data = new ValidationData();
|
||||
$data->setCurrentTime(time());
|
||||
|
||||
if ($token->validate($data) === false) {
|
||||
throw OAuthServerException::accessDenied('Access token is invalid');
|
||||
}
|
||||
|
||||
// Check if token has been revoked
|
||||
if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) {
|
||||
throw OAuthServerException::accessDenied('Access token has been revoked');
|
||||
}
|
||||
|
||||
// Return the request with additional attributes
|
||||
return $request
|
||||
->withAttribute('oauth_access_token_id', $token->getClaim('jti'))
|
||||
->withAttribute('oauth_client_id', $token->getClaim('aud'))
|
||||
->withAttribute('oauth_user_id', $token->getClaim('sub'))
|
||||
->withAttribute('oauth_scopes', $token->getClaim('scopes'));
|
||||
} 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');
|
||||
}
|
||||
}
|
||||
}
|
118
src/CryptKey.php
118
src/CryptKey.php
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Cryptography key holder.
|
||||
*
|
||||
* @author Julián Gutiérrez <juliangut@gmail.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
class CryptKey
|
||||
{
|
||||
const RSA_KEY_PATTERN =
|
||||
'/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----\n)(.|\n)+(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)$/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $keyPath;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
protected $passPhrase;
|
||||
|
||||
/**
|
||||
* @param string $keyPath
|
||||
* @param null|string $passPhrase
|
||||
* @param bool $keyPermissionsCheck
|
||||
*/
|
||||
public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true)
|
||||
{
|
||||
if (preg_match(self::RSA_KEY_PATTERN, $keyPath)) {
|
||||
$keyPath = $this->saveKeyToFile($keyPath);
|
||||
}
|
||||
|
||||
if (strpos($keyPath, 'file://') !== 0) {
|
||||
$keyPath = 'file://' . $keyPath;
|
||||
}
|
||||
|
||||
if (!file_exists($keyPath) || !is_readable($keyPath)) {
|
||||
throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath));
|
||||
}
|
||||
|
||||
if ($keyPermissionsCheck === true) {
|
||||
// Verify the permissions of the key
|
||||
$keyPathPerms = decoct(fileperms($keyPath) & 0777);
|
||||
if (in_array($keyPathPerms, ['600', '660'], true) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
trigger_error(sprintf(
|
||||
'Key file "%s" permissions are not correct, should be 600 or 660 instead of %s',
|
||||
$keyPath,
|
||||
$keyPathPerms
|
||||
), E_USER_NOTICE);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
$this->keyPath = $keyPath;
|
||||
$this->passPhrase = $passPhrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function saveKeyToFile($key)
|
||||
{
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
$keyPath = $tmpDir . '/' . sha1($key) . '.key';
|
||||
|
||||
if (!file_exists($keyPath) && !touch($keyPath)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('"%s" key file could not be created', $keyPath);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (file_put_contents($keyPath, $key) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to write key file to temporary directory "%s"', $tmpDir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (chmod($keyPath, 0600) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('The key file "%s" file mode could not be changed with chmod to 600', $keyPath);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return 'file://' . $keyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve key path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyPath()
|
||||
{
|
||||
return $this->keyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve key pass phrase.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getPassPhrase()
|
||||
{
|
||||
return $this->passPhrase;
|
||||
}
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Public/private key encryption.
|
||||
*
|
||||
* @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 Defuse\Crypto\Crypto;
|
||||
|
||||
trait CryptTrait
|
||||
{
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
protected $privateKey;
|
||||
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
protected $publicKey;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $encryptionKey;
|
||||
|
||||
/**
|
||||
* Set path to private key.
|
||||
*
|
||||
* @param CryptKey $privateKey
|
||||
*/
|
||||
public function setPrivateKey(CryptKey $privateKey)
|
||||
{
|
||||
$this->privateKey = $privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to public key.
|
||||
*
|
||||
* @param CryptKey $publicKey
|
||||
*/
|
||||
public function setPublicKey(CryptKey $publicKey)
|
||||
{
|
||||
$this->publicKey = $publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data with a private key.
|
||||
*
|
||||
* @param string $unencryptedData
|
||||
*
|
||||
* @throws \LogicException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encrypt($unencryptedData)
|
||||
{
|
||||
if ($this->encryptionKey !== null) {
|
||||
return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
$privateKey = openssl_pkey_get_private($this->privateKey->getKeyPath(), $this->privateKey->getPassPhrase());
|
||||
$privateKeyDetails = @openssl_pkey_get_details($privateKey);
|
||||
if ($privateKeyDetails === null) {
|
||||
throw new \LogicException(
|
||||
sprintf('Could not get details of private key: %s', $this->privateKey->getKeyPath())
|
||||
);
|
||||
}
|
||||
|
||||
$chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11;
|
||||
$output = '';
|
||||
|
||||
while ($unencryptedData) {
|
||||
$chunk = substr($unencryptedData, 0, $chunkSize);
|
||||
$unencryptedData = substr($unencryptedData, $chunkSize);
|
||||
if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \LogicException('Failed to encrypt data');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$output .= $encrypted;
|
||||
}
|
||||
openssl_pkey_free($privateKey);
|
||||
|
||||
return base64_encode($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data with a public key.
|
||||
*
|
||||
* @param string $encryptedData
|
||||
*
|
||||
* @throws \LogicException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function decrypt($encryptedData)
|
||||
{
|
||||
if ($this->encryptionKey !== null) {
|
||||
return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
|
||||
}
|
||||
|
||||
$publicKey = openssl_pkey_get_public($this->publicKey->getKeyPath());
|
||||
$publicKeyDetails = @openssl_pkey_get_details($publicKey);
|
||||
if ($publicKeyDetails === null) {
|
||||
throw new \LogicException(
|
||||
sprintf('Could not get details of public key: %s', $this->publicKey->getKeyPath())
|
||||
);
|
||||
}
|
||||
|
||||
$chunkSize = ceil($publicKeyDetails['bits'] / 8);
|
||||
$output = '';
|
||||
|
||||
$encryptedData = base64_decode($encryptedData);
|
||||
|
||||
while ($encryptedData) {
|
||||
$chunk = substr($encryptedData, 0, $chunkSize);
|
||||
$encryptedData = substr($encryptedData, $chunkSize);
|
||||
if (openssl_public_decrypt($chunk, $decrypted, $publicKey/*, OPENSSL_PKCS1_OAEP_PADDING*/) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \LogicException('Failed to decrypt data');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$output .= $decrypted;
|
||||
}
|
||||
openssl_pkey_free($publicKey);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encryption key
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function setEncryptionKey($key = null)
|
||||
{
|
||||
$this->encryptionKey = $key;
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
|
||||
interface AccessTokenEntityInterface extends TokenInterface
|
||||
{
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
* @param CryptKey $privateKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertToJWT(CryptKey $privateKey);
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface AuthCodeEntityInterface extends TokenInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri();
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setRedirectUri($uri);
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface ClientEntityInterface
|
||||
{
|
||||
/**
|
||||
* Get the client's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Get the client's name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Returns the registered redirect URI (as a string).
|
||||
*
|
||||
* Alternatively return an indexed array of redirect URIs.
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
public function getRedirectUri();
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface RefreshTokenEntityInterface
|
||||
{
|
||||
/**
|
||||
* Get the token's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the token's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* Set the access token that the refresh token was associated with.
|
||||
*
|
||||
* @param AccessTokenEntityInterface $accessToken
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken);
|
||||
|
||||
/**
|
||||
* Get the access token that the refresh token was originally associated with.
|
||||
*
|
||||
* @return AccessTokenEntityInterface
|
||||
*/
|
||||
public function getAccessToken();
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface ScopeEntityInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Get the scope's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface TokenInterface
|
||||
{
|
||||
/**
|
||||
* Get the token's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the token's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* Set the identifier of the user associated with the token.
|
||||
*
|
||||
* @param string|int $identifier The identifier of the user
|
||||
*/
|
||||
public function setUserIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token user's identifier.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function getUserIdentifier();
|
||||
|
||||
/**
|
||||
* Get the client that the token was issued to.
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClient();
|
||||
|
||||
/**
|
||||
* Set the client that the token was issued to.
|
||||
*
|
||||
* @param ClientEntityInterface $client
|
||||
*/
|
||||
public function setClient(ClientEntityInterface $client);
|
||||
|
||||
/**
|
||||
* Associate a scope with the token.
|
||||
*
|
||||
* @param ScopeEntityInterface $scope
|
||||
*/
|
||||
public function addScope(ScopeEntityInterface $scope);
|
||||
|
||||
/**
|
||||
* Return an array of scopes associated with the token.
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes();
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
<?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;
|
||||
|
||||
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
|
||||
{
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
* @param CryptKey $privateKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertToJWT(CryptKey $privateKey)
|
||||
{
|
||||
return (new Builder())
|
||||
->setAudience($this->getClient()->getIdentifier())
|
||||
->setId($this->getIdentifier(), true)
|
||||
->setIssuedAt(time())
|
||||
->setNotBefore(time())
|
||||
->setExpiration($this->getExpiryDateTime()->getTimestamp())
|
||||
->setSubject($this->getUserIdentifier())
|
||||
->set('scopes', $this->getScopes())
|
||||
->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,34 +0,0 @@
|
||||
<?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;
|
||||
|
||||
trait AuthCodeTrait
|
||||
{
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
protected $redirectUri;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setRedirectUri($uri)
|
||||
{
|
||||
$this->redirectUri = $uri;
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
<?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;
|
||||
|
||||
trait ClientTrait
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected $redirectUri;
|
||||
|
||||
/**
|
||||
* Get the client's name.
|
||||
*
|
||||
* @return string
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered redirect URI (as a string).
|
||||
*
|
||||
* Alternatively return an indexed array of redirect URIs.
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
<?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;
|
||||
|
||||
trait EntityTrait
|
||||
{
|
||||
/*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
|
||||
trait RefreshTokenTrait
|
||||
{
|
||||
/**
|
||||
* @var AccessTokenEntityInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
return $this->expiryDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
}
|
@@ -1,116 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
trait TokenEntityTrait
|
||||
{
|
||||
/**
|
||||
* @var ScopeEntityInterface[]
|
||||
*/
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
/**
|
||||
* @var string|int
|
||||
*/
|
||||
protected $userIdentifier;
|
||||
|
||||
/**
|
||||
* @var ClientEntityInterface
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Associate a scope with the token.
|
||||
*
|
||||
* @param ScopeEntityInterface $scope
|
||||
*/
|
||||
public function addScope(ScopeEntityInterface $scope)
|
||||
{
|
||||
$this->scopes[$scope->getIdentifier()] = $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of scopes associated with the token.
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return array_values($this->scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
return $this->expiryDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of the user associated with the token.
|
||||
*
|
||||
* @param string|int $identifier The identifier of the user
|
||||
*/
|
||||
public function setUserIdentifier($identifier)
|
||||
{
|
||||
$this->userIdentifier = $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token user's identifier.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function getUserIdentifier()
|
||||
{
|
||||
return $this->userIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client that the token was issued to.
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client that the token was issued to.
|
||||
*
|
||||
* @param ClientEntityInterface $client
|
||||
*/
|
||||
public function setClient(ClientEntityInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?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;
|
||||
|
||||
interface UserEntityInterface
|
||||
{
|
||||
/**
|
||||
* Return the user's identifier.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier();
|
||||
}
|
@@ -1,296 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class OAuthServerException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $httpStatusCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $errorType;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $hint;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $redirectUri;
|
||||
|
||||
/**
|
||||
* Throw a new exception.
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
* @param string $errorType Error type
|
||||
* @param int $httpStatusCode HTTP status code to send (default = 400)
|
||||
* @param null|string $hint A helper hint
|
||||
* @param null|string $redirectUri A HTTP URI to redirect the user back to
|
||||
*/
|
||||
public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
$this->httpStatusCode = $httpStatusCode;
|
||||
$this->errorType = $errorType;
|
||||
$this->hint = $hint;
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported grant type error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function unsupportedGrantType()
|
||||
{
|
||||
$errorMessage = 'The authorization grant type is not supported by the authorization server.';
|
||||
$hint = 'Check the `grant_type` parameter';
|
||||
|
||||
return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid request error.
|
||||
*
|
||||
* @param string $parameter The invalid parameter
|
||||
* @param null|string $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidRequest($parameter, $hint = null)
|
||||
{
|
||||
$errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
|
||||
'includes a parameter more than once, or is otherwise malformed.';
|
||||
$hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
|
||||
|
||||
return new static($errorMessage, 3, 'invalid_request', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid client error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidClient()
|
||||
{
|
||||
$errorMessage = 'Client authentication failed';
|
||||
|
||||
return new static($errorMessage, 4, 'invalid_client', 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid scope error.
|
||||
*
|
||||
* @param string $scope The bad scope
|
||||
* @param null|string $redirectUri A HTTP URI to redirect the user back to
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidScope($scope, $redirectUri = null)
|
||||
{
|
||||
$errorMessage = 'The requested scope is invalid, unknown, or malformed';
|
||||
$hint = sprintf(
|
||||
'Check the `%s` scope',
|
||||
htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
|
||||
);
|
||||
|
||||
return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid credentials error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidCredentials()
|
||||
{
|
||||
return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server error.
|
||||
*
|
||||
* @param $hint
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public static function serverError($hint)
|
||||
{
|
||||
return new static(
|
||||
'The authorization server encountered an unexpected condition which prevented it from fulfilling'
|
||||
. ' the request: ' . $hint,
|
||||
7,
|
||||
'server_error',
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid refresh token.
|
||||
*
|
||||
* @param null|string $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidRefreshToken($hint = null)
|
||||
{
|
||||
return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access denied.
|
||||
*
|
||||
* @param null|string $hint
|
||||
* @param null|string $redirectUri
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function accessDenied($hint = null, $redirectUri = null)
|
||||
{
|
||||
return new static(
|
||||
'The resource owner or authorization server denied the request.',
|
||||
9,
|
||||
'access_denied',
|
||||
401,
|
||||
$hint,
|
||||
$redirectUri
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function getErrorType()
|
||||
{
|
||||
return $this->errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HTTP response.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param bool $useFragment True if errors should be in the URI fragment instead of query string
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response, $useFragment = false)
|
||||
{
|
||||
$headers = $this->getHttpHeaders();
|
||||
|
||||
$payload = [
|
||||
'error' => $this->getErrorType(),
|
||||
'message' => $this->getMessage(),
|
||||
];
|
||||
|
||||
if ($this->hint !== null) {
|
||||
$payload['hint'] = $this->hint;
|
||||
}
|
||||
|
||||
if ($this->redirectUri !== null) {
|
||||
if ($useFragment === true) {
|
||||
$this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
|
||||
} else {
|
||||
$this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
|
||||
}
|
||||
|
||||
return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
|
||||
}
|
||||
|
||||
foreach ($headers as $header => $content) {
|
||||
$response = $response->withHeader($header, $content);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode($payload));
|
||||
|
||||
return $response->withStatus($this->getHttpStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response.
|
||||
*
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public function getHttpHeaders()
|
||||
{
|
||||
$headers = [
|
||||
'Content-type' => 'application/json',
|
||||
];
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->errorType === 'invalid_client') {
|
||||
$authScheme = 'Basic';
|
||||
if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false
|
||||
&& strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0
|
||||
) {
|
||||
$authScheme = 'Bearer';
|
||||
}
|
||||
$headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code to send when the exceptions is output.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHttpStatusCode()
|
||||
{
|
||||
return $this->httpStatusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getHint()
|
||||
{
|
||||
return $this->hint;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Abstract authorization grant.
|
||||
*
|
||||
* @author Julián Gutiérrez <juliangut@gmail.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
abstract class AbstractAuthorizeGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
* @param string $queryDelimiter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function makeRedirectUri($uri, $params = [], $queryDelimiter = '?')
|
||||
{
|
||||
$uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&';
|
||||
|
||||
return $uri . http_build_query($params);
|
||||
}
|
||||
}
|
@@ -1,496 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract grant.
|
||||
*
|
||||
* @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\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
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;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Abstract grant class.
|
||||
*/
|
||||
abstract class AbstractGrant implements GrantTypeInterface
|
||||
{
|
||||
use EmitterAwareTrait, CryptTrait;
|
||||
|
||||
const SCOPE_DELIMITER_STRING = ' ';
|
||||
|
||||
const MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS = 10;
|
||||
|
||||
/**
|
||||
* @var ClientRepositoryInterface
|
||||
*/
|
||||
protected $clientRepository;
|
||||
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
protected $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var ScopeRepositoryInterface
|
||||
*/
|
||||
protected $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var AuthCodeRepositoryInterface
|
||||
*/
|
||||
protected $authCodeRepository;
|
||||
|
||||
/**
|
||||
* @var RefreshTokenRepositoryInterface
|
||||
*/
|
||||
protected $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* @var UserRepositoryInterface
|
||||
*/
|
||||
protected $userRepository;
|
||||
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
protected $refreshTokenTTL;
|
||||
|
||||
/**
|
||||
* @param ClientRepositoryInterface $clientRepository
|
||||
*/
|
||||
public function setClientRepository(ClientRepositoryInterface $clientRepository)
|
||||
{
|
||||
$this->clientRepository = $clientRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository)
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScopeRepositoryInterface $scopeRepository
|
||||
*/
|
||||
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository)
|
||||
{
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AuthCodeRepositoryInterface $authCodeRepository
|
||||
*/
|
||||
public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository)
|
||||
{
|
||||
$this->authCodeRepository = $authCodeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserRepositoryInterface $userRepository
|
||||
*/
|
||||
public function setUserRepository(UserRepositoryInterface $userRepository)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
||||
{
|
||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
|
||||
|
||||
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
// If the client is confidential require the client secret
|
||||
$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
$clientSecret,
|
||||
true
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
// If a redirect URI is provided ensure it matches what is pre-registered
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if ($redirectUri !== null) {
|
||||
if (
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$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(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scopes in the request.
|
||||
*
|
||||
* @param string $scopes
|
||||
* @param string $redirectUri
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function validateScopes(
|
||||
$scopes,
|
||||
$redirectUri = null
|
||||
) {
|
||||
$scopesList = array_filter(
|
||||
explode(self::SCOPE_DELIMITER_STRING, trim($scopes)),
|
||||
function ($scope) {
|
||||
return !empty($scope);
|
||||
}
|
||||
);
|
||||
|
||||
$scopes = [];
|
||||
foreach ($scopesList as $scopeItem) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
|
||||
|
||||
if ($scope instanceof ScopeEntityInterface === false) {
|
||||
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
||||
}
|
||||
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve request parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
|
||||
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 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.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cookie parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve server parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getServerParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token.
|
||||
*
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
* @param ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||
*
|
||||
* @return AccessTokenEntityInterface
|
||||
*/
|
||||
protected function issueAccessToken(
|
||||
\DateInterval $accessTokenTTL,
|
||||
ClientEntityInterface $client,
|
||||
$userIdentifier,
|
||||
array $scopes = []
|
||||
) {
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL));
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
|
||||
return $accessToken;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an auth code.
|
||||
*
|
||||
* @param \DateInterval $authCodeTTL
|
||||
* @param ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
* @param string $redirectUri
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||
*
|
||||
* @return AuthCodeEntityInterface
|
||||
*/
|
||||
protected function issueAuthCode(
|
||||
\DateInterval $authCodeTTL,
|
||||
ClientEntityInterface $client,
|
||||
$userIdentifier,
|
||||
$redirectUri,
|
||||
array $scopes = []
|
||||
) {
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$authCode = $this->authCodeRepository->getNewAuthCode();
|
||||
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
$authCode->setRedirectUri($redirectUri);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$authCode->addScope($scope);
|
||||
}
|
||||
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
|
||||
return $authCode;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccessTokenEntityInterface $accessToken
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
* @throws UniqueTokenIdentifierConstraintViolationException
|
||||
*
|
||||
* @return RefreshTokenEntityInterface
|
||||
*/
|
||||
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||
|
||||
$refreshToken = $this->refreshTokenRepository->getNewRefreshToken();
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
|
||||
while ($maxGenerationAttempts-- > 0) {
|
||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
try {
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
|
||||
return $refreshToken;
|
||||
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||
if ($maxGenerationAttempts === 0) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new unique identifier.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateUniqueIdentifier($length = 40)
|
||||
{
|
||||
try {
|
||||
return bin2hex(random_bytes($length));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\TypeError $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Error $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Exception $e) {
|
||||
// If you get this message, the CSPRNG failed hard.
|
||||
throw OAuthServerException::serverError('Could not generate a random string');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToAccessTokenRequest(ServerRequestInterface $request)
|
||||
{
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
|
||||
return (
|
||||
array_key_exists('grant_type', $requestParameters)
|
||||
&& $requestParameters['grant_type'] === $this->getIdentifier()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
throw new \LogicException('This grant cannot validate an authorization request');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
|
||||
{
|
||||
throw new \LogicException('This grant cannot complete an authorization request');
|
||||
}
|
||||
}
|
@@ -1,368 +0,0 @@
|
||||
<?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\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\ResponseTypes\RedirectResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
{
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
private $authCodeTTL;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $enableCodeExchangeProof = false;
|
||||
|
||||
/**
|
||||
* @param AuthCodeRepositoryInterface $authCodeRepository
|
||||
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
* @param \DateInterval $authCodeTTL
|
||||
*/
|
||||
public function __construct(
|
||||
AuthCodeRepositoryInterface $authCodeRepository,
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository,
|
||||
\DateInterval $authCodeTTL
|
||||
) {
|
||||
$this->setAuthCodeRepository($authCodeRepository);
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
$this->authCodeTTL = $authCodeTTL;
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
public function enableCodeExchangeProof()
|
||||
{
|
||||
$this->enableCodeExchangeProof = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to an access token request.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$encryptedAuthCode = $this->getRequestParameter('code', $request, null);
|
||||
|
||||
if ($encryptedAuthCode === null) {
|
||||
throw OAuthServerException::invalidRequest('code');
|
||||
}
|
||||
|
||||
// Validate the authorization code
|
||||
try {
|
||||
$authCodePayload = json_decode($this->decrypt($encryptedAuthCode));
|
||||
if (time() > $authCodePayload->expire_time) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
|
||||
}
|
||||
|
||||
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
|
||||
}
|
||||
|
||||
if ($authCodePayload->client_id !== $client->getIdentifier()) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
|
||||
}
|
||||
|
||||
// The redirect URI is required in this request
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri');
|
||||
}
|
||||
|
||||
if ($authCodePayload->redirect_uri !== $redirectUri) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
|
||||
}
|
||||
|
||||
$scopes = [];
|
||||
foreach ($authCodePayload->scopes as $scopeId) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if ($scope instanceof ScopeEntityInterface === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes(
|
||||
$scopes,
|
||||
$this->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);
|
||||
|
||||
// Inject tokens into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
// Revoke used auth code
|
||||
$this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'authorization_code';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return (
|
||||
array_key_exists('response_type', $request->getQueryParams())
|
||||
&& $request->getQueryParams()['response_type'] === 'code'
|
||||
&& isset($request->getQueryParams()['client_id'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
$clientId = $this->getQueryStringParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
||||
if ($redirectUri !== null) {
|
||||
if (
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$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(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
: $client->getRedirectUri()
|
||||
);
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
|
||||
$authorizationRequest = new AuthorizationRequest();
|
||||
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
||||
$authorizationRequest->setClient($client);
|
||||
$authorizationRequest->setRedirectUri($redirectUri);
|
||||
$authorizationRequest->setState($stateParameter);
|
||||
$authorizationRequest->setScopes($scopes);
|
||||
|
||||
if ($this->enableCodeExchangeProof === true) {
|
||||
$codeChallenge = $this->getQueryStringParameter('code_challenge', $request);
|
||||
if ($codeChallenge === null) {
|
||||
throw OAuthServerException::invalidRequest('code_challenge');
|
||||
}
|
||||
|
||||
if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeChallenge) !== 1) {
|
||||
throw OAuthServerException::invalidRequest(
|
||||
'code_challenge',
|
||||
'The code_challenge must be between 43 and 128 characters'
|
||||
);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
|
||||
{
|
||||
if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) {
|
||||
throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest');
|
||||
}
|
||||
|
||||
$finalRedirectUri = ($authorizationRequest->getRedirectUri() === null)
|
||||
? is_array($authorizationRequest->getClient()->getRedirectUri())
|
||||
? $authorizationRequest->getClient()->getRedirectUri()[0]
|
||||
: $authorizationRequest->getClient()->getRedirectUri()
|
||||
: $authorizationRequest->getRedirectUri();
|
||||
|
||||
// The user approved the client, redirect them back with an auth code
|
||||
if ($authorizationRequest->isAuthorizationApproved() === true) {
|
||||
$authCode = $this->issueAuthCode(
|
||||
$this->authCodeTTL,
|
||||
$authorizationRequest->getClient(),
|
||||
$authorizationRequest->getUser()->getIdentifier(),
|
||||
$authorizationRequest->getRedirectUri(),
|
||||
$authorizationRequest->getScopes()
|
||||
);
|
||||
|
||||
$payload = [
|
||||
'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(),
|
||||
];
|
||||
|
||||
if ($this->encryptionKey === null) {
|
||||
// Add padding to vary the length of the payload
|
||||
$payload['_padding'] = base64_encode(random_bytes(mt_rand(8, 256)));
|
||||
// Shuffle the payload so that the structure is no longer know and obvious
|
||||
$keys = array_keys($payload);
|
||||
shuffle($keys);
|
||||
$shuffledPayload = [];
|
||||
foreach ($keys as $key) {
|
||||
$shuffledPayload[$key] = $payload[$key];
|
||||
}
|
||||
} else {
|
||||
$shuffledPayload = $payload;
|
||||
}
|
||||
|
||||
$response = new RedirectResponse();
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'code' => $this->encrypt(
|
||||
json_encode(
|
||||
$shuffledPayload
|
||||
)
|
||||
),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied(
|
||||
'The user denied the request',
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant.
|
||||
*
|
||||
* @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\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class.
|
||||
*/
|
||||
class ClientCredentialsGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);
|
||||
|
||||
// Issue and persist access token
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $scopes);
|
||||
|
||||
// Inject access token into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'client_credentials';
|
||||
}
|
||||
}
|
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Grant type 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\Grant;
|
||||
|
||||
use League\Event\EmitterAwareInterface;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Grant type interface.
|
||||
*/
|
||||
interface GrantTypeInterface extends EmitterAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set refresh token TTL.
|
||||
*
|
||||
* @param \DateInterval $refreshTokenTTL
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL);
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Respond to an incoming request.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
);
|
||||
|
||||
/**
|
||||
* The grant type should return true if it is able to response to an authorization request
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canRespondToAuthorizationRequest(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* If the grant can respond to an authorization request this method should be called to validate the parameters of
|
||||
* the request.
|
||||
*
|
||||
* If the validation is successful an AuthorizationRequest object will be returned. This object can be safely
|
||||
* serialized in a user's session, and can be used during user authentication and authorization.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return AuthorizationRequest
|
||||
*/
|
||||
public function validateAuthorizationRequest(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* Once a user has authenticated and authorized the client the grant can complete the authorization request.
|
||||
* The AuthorizationRequest object's $userId property must be set to the authenticated user and the
|
||||
* $authorizationApproved property must reflect their desire to authorize or deny the client.
|
||||
*
|
||||
* @param AuthorizationRequest $authorizationRequest
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest);
|
||||
|
||||
/**
|
||||
* The grant type should return true if it is able to respond to this request.
|
||||
*
|
||||
* For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canRespondToAccessTokenRequest(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* Set the client repository.
|
||||
*
|
||||
* @param ClientRepositoryInterface $clientRepository
|
||||
*/
|
||||
public function setClientRepository(ClientRepositoryInterface $clientRepository);
|
||||
|
||||
/**
|
||||
* Set the access token repository.
|
||||
*
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository);
|
||||
|
||||
/**
|
||||
* Set the scope repository.
|
||||
*
|
||||
* @param ScopeRepositoryInterface $scopeRepository
|
||||
*/
|
||||
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
|
||||
|
||||
/**
|
||||
* Set the path to the private key.
|
||||
*
|
||||
* @param CryptKey $privateKey
|
||||
*/
|
||||
public function setPrivateKey(CryptKey $privateKey);
|
||||
|
||||
/**
|
||||
* Set the path to the public key.
|
||||
*
|
||||
* @param CryptKey $publicKey
|
||||
*/
|
||||
public function setPublicKey(CryptKey $publicKey);
|
||||
|
||||
/**
|
||||
* Set the encryption key
|
||||
*
|
||||
* @param string|null $key
|
||||
*/
|
||||
public function setEncryptionKey($key = null);
|
||||
}
|
@@ -1,225 +0,0 @@
|
||||
<?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;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
{
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
private $accessTokenTTL;
|
||||
|
||||
/**
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*/
|
||||
public function __construct(\DateInterval $accessTokenTTL)
|
||||
{
|
||||
$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 RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*
|
||||
* @throw \LogicException
|
||||
*/
|
||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
throw new \LogicException('The Implicit Grant does not return refresh tokens');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToAccessTokenRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'implicit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to an incoming request.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
throw new \LogicException('This grant does not used this method');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return (
|
||||
array_key_exists('response_type', $request->getQueryParams())
|
||||
&& $request->getQueryParams()['response_type'] === 'token'
|
||||
&& isset($request->getQueryParams()['client_id'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorizationRequest(ServerRequestInterface $request)
|
||||
{
|
||||
$clientId = $this->getQueryStringParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
|
||||
if ($redirectUri !== null) {
|
||||
if (
|
||||
is_string($client->getRedirectUri())
|
||||
&& (strcmp($client->getRedirectUri(), $redirectUri) !== 0)
|
||||
) {
|
||||
$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(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
is_array($client->getRedirectUri())
|
||||
? $client->getRedirectUri()[0]
|
||||
: $client->getRedirectUri()
|
||||
);
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes(
|
||||
$scopes,
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
|
||||
$authorizationRequest = new AuthorizationRequest();
|
||||
$authorizationRequest->setGrantTypeId($this->getIdentifier());
|
||||
$authorizationRequest->setClient($client);
|
||||
$authorizationRequest->setRedirectUri($redirectUri);
|
||||
$authorizationRequest->setState($stateParameter);
|
||||
$authorizationRequest->setScopes($scopes);
|
||||
|
||||
return $authorizationRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest)
|
||||
{
|
||||
if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) {
|
||||
throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest');
|
||||
}
|
||||
|
||||
$finalRedirectUri = ($authorizationRequest->getRedirectUri() === null)
|
||||
? is_array($authorizationRequest->getClient()->getRedirectUri())
|
||||
? $authorizationRequest->getClient()->getRedirectUri()[0]
|
||||
: $authorizationRequest->getClient()->getRedirectUri()
|
||||
: $authorizationRequest->getRedirectUri();
|
||||
|
||||
// The user approved the client, redirect them back with an access token
|
||||
if ($authorizationRequest->isAuthorizationApproved() === true) {
|
||||
$accessToken = $this->issueAccessToken(
|
||||
$this->accessTokenTTL,
|
||||
$authorizationRequest->getClient(),
|
||||
$authorizationRequest->getUser()->getIdentifier(),
|
||||
$authorizationRequest->getScopes()
|
||||
);
|
||||
|
||||
$response = new RedirectResponse();
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'access_token' => (string) $accessToken->convertToJWT($this->privateKey),
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(),
|
||||
'state' => $authorizationRequest->getState(),
|
||||
],
|
||||
'#'
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied(
|
||||
'The user denied the request',
|
||||
$this->makeRedirectUri(
|
||||
$finalRedirectUri,
|
||||
[
|
||||
'state' => $authorizationRequest->getState(),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Password grant.
|
||||
*
|
||||
* @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\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Password grant class.
|
||||
*/
|
||||
class PasswordGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @param UserRepositoryInterface $userRepository
|
||||
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function __construct(
|
||||
UserRepositoryInterface $userRepository,
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
) {
|
||||
$this->setUserRepository($userRepository);
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
||||
$user = $this->validateUser($request, $client);
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
||||
|
||||
// Issue and persist new tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
|
||||
// Inject tokens into response
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ClientEntityInterface $client
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return UserEntityInterface
|
||||
*/
|
||||
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
|
||||
{
|
||||
$username = $this->getRequestParameter('username', $request);
|
||||
if (is_null($username)) {
|
||||
throw OAuthServerException::invalidRequest('username');
|
||||
}
|
||||
|
||||
$password = $this->getRequestParameter('password', $request);
|
||||
if (is_null($password)) {
|
||||
throw OAuthServerException::invalidRequest('password');
|
||||
}
|
||||
|
||||
$user = $this->userRepository->getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
if ($user instanceof UserEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
|
||||
|
||||
throw OAuthServerException::invalidCredentials();
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
}
|
@@ -1,133 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token grant.
|
||||
*
|
||||
* @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\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Refresh token grant.
|
||||
*/
|
||||
class RefreshTokenGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
||||
|
||||
// If no new scopes are requested then give the access token the original session scopes
|
||||
if (count($scopes) === 0) {
|
||||
$scopes = array_map(function ($scopeId) use ($client) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if ($scope instanceof ScopeEntityInterface === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}, $oldRefreshToken['scopes']);
|
||||
} else {
|
||||
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
||||
// the request doesn't include any new scopes
|
||||
foreach ($scopes as $scope) {
|
||||
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) {
|
||||
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expire old tokens
|
||||
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
||||
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
|
||||
|
||||
// Issue and persist new tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
|
||||
// Inject tokens into response
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param string $clientId
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId)
|
||||
{
|
||||
$encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request);
|
||||
if (is_null($encryptedRefreshToken)) {
|
||||
throw OAuthServerException::invalidRequest('refresh_token');
|
||||
}
|
||||
|
||||
// Validate refresh token
|
||||
try {
|
||||
$refreshToken = $this->decrypt($encryptedRefreshToken);
|
||||
} catch (\Exception $e) {
|
||||
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token');
|
||||
}
|
||||
|
||||
$refreshTokenData = json_decode($refreshToken, true);
|
||||
if ($refreshTokenData['client_id'] !== $clientId) {
|
||||
$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()) {
|
||||
throw OAuthServerException::invalidRefreshToken('Token has expired');
|
||||
}
|
||||
|
||||
if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) {
|
||||
throw OAuthServerException::invalidRefreshToken('Token has been revoked');
|
||||
}
|
||||
|
||||
return $refreshTokenData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'refresh_token';
|
||||
}
|
||||
}
|
479
src/League/OAuth2/Server/Authorization.php
Normal file
479
src/League/OAuth2/Server/Authorization.php
Normal file
@@ -0,0 +1,479 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Authorization Server
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use League\OAuth2\Server\Util\Request;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 authorization server class
|
||||
*/
|
||||
class Authorization
|
||||
{
|
||||
/**
|
||||
* The delimeter between scopes specified in the scope query string parameter
|
||||
*
|
||||
* The OAuth 2 specification states it should be a space but most use a comma
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeDelimeter = ' ';
|
||||
|
||||
/**
|
||||
* The TTL (time to live) of an access token in seconds (default: 3600)
|
||||
* @var integer
|
||||
*/
|
||||
protected $accessTokenTTL = 3600;
|
||||
|
||||
/**
|
||||
* The registered grant response types
|
||||
* @var array
|
||||
*/
|
||||
protected $responseTypes = array();
|
||||
|
||||
/**
|
||||
* The client, scope and session storage classes
|
||||
* @var array
|
||||
*/
|
||||
protected $storages = array();
|
||||
|
||||
/**
|
||||
* The registered grant types
|
||||
* @var array
|
||||
*/
|
||||
protected $grantTypes = array();
|
||||
|
||||
/**
|
||||
* Require the "scope" parameter to be in checkAuthoriseParams()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireScopeParam = false;
|
||||
|
||||
/**
|
||||
* Default scope(s) to be used if none is provided
|
||||
* @var string|array
|
||||
*/
|
||||
protected $defaultScope = null;
|
||||
|
||||
/**
|
||||
* Require the "state" parameter to be in checkAuthoriseParams()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireStateParam = false;
|
||||
|
||||
/**
|
||||
* The request object
|
||||
* @var Util\RequestInterface
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionCodes = array(
|
||||
0 => 'invalid_request',
|
||||
1 => 'unauthorized_client',
|
||||
2 => 'access_denied',
|
||||
3 => 'unsupported_response_type',
|
||||
4 => 'invalid_scope',
|
||||
5 => 'server_error',
|
||||
6 => 'temporarily_unavailable',
|
||||
7 => 'unsupported_grant_type',
|
||||
8 => 'invalid_client',
|
||||
9 => 'invalid_grant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error messages
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionMessages = array(
|
||||
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
'unauthorized_client' => 'The client is not authorized to request an access token using this method.',
|
||||
'access_denied' => 'The resource owner or authorization server denied the request.',
|
||||
'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.',
|
||||
'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.',
|
||||
'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.',
|
||||
'temporarily_unavailable' => 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.',
|
||||
'unsupported_grant_type' => 'The authorization grant type "%s" is not supported by the authorization server',
|
||||
'invalid_client' => 'Client authentication failed',
|
||||
'invalid_grant' => 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. Check the "%s" parameter.',
|
||||
'invalid_credentials' => 'The user credentials were incorrect.',
|
||||
'invalid_refresh' => 'The refresh token is invalid.',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error HTTP status codes
|
||||
* @var array
|
||||
*
|
||||
* RFC 6749, section 4.1.2.1.:
|
||||
* No 503 status code for 'temporarily_unavailable', because
|
||||
* "a 503 Service Unavailable HTTP status code cannot be
|
||||
* returned to the client via an HTTP redirect"
|
||||
*/
|
||||
protected static $exceptionHttpStatusCodes = array(
|
||||
'invalid_request' => 400,
|
||||
'unauthorized_client' => 400,
|
||||
'access_denied' => 401,
|
||||
'unsupported_response_type' => 400,
|
||||
'invalid_scope' => 400,
|
||||
'server_error' => 500,
|
||||
'temporarily_unavailable' => 400,
|
||||
'unsupported_grant_type' => 501,
|
||||
'invalid_client' => 401,
|
||||
'invalid_grant' => 400,
|
||||
'invalid_credentials' => 400,
|
||||
'invalid_refresh' => 400,
|
||||
);
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public static function getExceptionHttpHeaders($error)
|
||||
{
|
||||
$headers = array();
|
||||
switch (self::$exceptionHttpStatusCodes[$error]) {
|
||||
case 401:
|
||||
$headers[] = 'HTTP/1.1 401 Unauthorized';
|
||||
break;
|
||||
case 500:
|
||||
$headers[] = 'HTTP/1.1 500 Internal Server Error';
|
||||
break;
|
||||
case 501:
|
||||
$headers[] = 'HTTP/1.1 501 Not Implemented';
|
||||
break;
|
||||
case 400:
|
||||
default:
|
||||
$headers[] = 'HTTP/1.1 400 Bad Request';
|
||||
}
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($error === 'invalid_client') {
|
||||
$authScheme = null;
|
||||
$request = new Request();
|
||||
if ($request->server('PHP_AUTH_USER') !== null) {
|
||||
$authScheme = 'Basic';
|
||||
} else {
|
||||
$authHeader = $request->header('Authorization');
|
||||
if ($authHeader !== null) {
|
||||
if (strpos($authHeader, 'Bearer') === 0) {
|
||||
$authScheme = 'Bearer';
|
||||
} elseif (strpos($authHeader, 'Basic') === 0) {
|
||||
$authScheme = 'Basic';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($authScheme !== null) {
|
||||
$headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""';
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception message
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return string The error message
|
||||
*/
|
||||
public static function getExceptionMessage($error = '')
|
||||
{
|
||||
return self::$exceptionMessages[$error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception code
|
||||
*
|
||||
* @param integer $code The exception code
|
||||
* @return string The exception code type
|
||||
*/
|
||||
public static function getExceptionType($code = 0)
|
||||
{
|
||||
return self::$exceptionCodes[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OAuth2 authorization server
|
||||
*
|
||||
* @param ClientInterface $client A class which inherits from Storage/ClientInterface
|
||||
* @param SessionInterface $session A class which inherits from Storage/SessionInterface
|
||||
* @param ScopeInterface $scope A class which inherits from Storage/ScopeInterface
|
||||
*/
|
||||
public function __construct(ClientInterface $client, SessionInterface $session, ScopeInterface $scope)
|
||||
{
|
||||
$this->storages = array(
|
||||
'client' => $client,
|
||||
'session' => $session,
|
||||
'scope' => $scope
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable support for a grant
|
||||
* @param GrantTypeInterface $grantType A grant class which conforms to Interface/GrantTypeInterface
|
||||
* @param null|string $identifier An identifier for the grant (autodetected if not passed)
|
||||
*/
|
||||
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||
{
|
||||
if (is_null($identifier)) {
|
||||
$identifier = $grantType->getIdentifier();
|
||||
}
|
||||
|
||||
// Inject server into grant
|
||||
$grantType->setAuthorizationServer($this);
|
||||
|
||||
$this->grantTypes[$identifier] = $grantType;
|
||||
|
||||
if ( ! is_null($grantType->getResponseType())) {
|
||||
$this->responseTypes[] = $grantType->getResponseType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a grant type has been enabled
|
||||
* @param string $identifier The grant type identifier
|
||||
* @return boolean Returns "true" if enabled, "false" if not
|
||||
*/
|
||||
public function hasGrantType($identifier)
|
||||
{
|
||||
return (array_key_exists($identifier, $this->grantTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResponseTypes()
|
||||
{
|
||||
return $this->responseTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "scope" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function requireScopeParam($require = true)
|
||||
{
|
||||
$this->requireScopeParam = $require;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the scope parameter required?
|
||||
* @return bool
|
||||
*/
|
||||
public function scopeParamRequired()
|
||||
{
|
||||
return $this->requireScopeParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default scope to be used if none is provided and requireScopeParam is false
|
||||
* @param string|array $default
|
||||
*/
|
||||
public function setDefaultScope($default = null)
|
||||
{
|
||||
$this->defaultScope = $default;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default scope to be used if none is provided and requireScopeParam is false
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultScope()
|
||||
{
|
||||
return $this->defaultScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function stateParamRequired()
|
||||
{
|
||||
return $this->requireStateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function requireStateParam($require = true)
|
||||
{
|
||||
$this->requireStateParam = $require;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope delimeter
|
||||
*
|
||||
* @return string The scope delimiter (default: ",")
|
||||
*/
|
||||
public function getScopeDelimeter()
|
||||
{
|
||||
return $this->scopeDelimeter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scope delimiter
|
||||
*
|
||||
* @param string $scopeDelimeter
|
||||
*/
|
||||
public function setScopeDelimeter($scopeDelimeter = ' ')
|
||||
{
|
||||
$this->scopeDelimeter = $scopeDelimeter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TTL for an access token
|
||||
* @return int The TTL
|
||||
*/
|
||||
public function getAccessTokenTTL()
|
||||
{
|
||||
return $this->accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TTL for an access token
|
||||
* @param int $accessTokenTTL The new TTL
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL = 3600)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Request Object
|
||||
*
|
||||
* @param Util\RequestInterface The Request Object
|
||||
*/
|
||||
public function setRequest(Util\RequestInterface $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Request object. It will create one from the globals if one is not set.
|
||||
*
|
||||
* @return Util\RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->request = Request::buildFromGlobals();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a storage class
|
||||
* @param string $obj The class required
|
||||
* @return Storage\ClientInterface|Storage\ScopeInterface|Storage\SessionInterface
|
||||
*/
|
||||
public function getStorage($obj)
|
||||
{
|
||||
return $this->storages[$obj];
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
*
|
||||
* @param array $inputParams Optional array of parsed $_POST keys
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function issueAccessToken($inputParams = array())
|
||||
{
|
||||
$grantType = $this->getParam('grant_type', 'post', $inputParams);
|
||||
|
||||
if (is_null($grantType)) {
|
||||
throw new Exception\ClientException(sprintf(self::$exceptionMessages['invalid_request'], 'grant_type'), 0);
|
||||
}
|
||||
|
||||
// Ensure grant type is one that is recognised and is enabled
|
||||
if ( ! in_array($grantType, array_keys($this->grantTypes))) {
|
||||
throw new Exception\ClientException(sprintf(self::$exceptionMessages['unsupported_grant_type'], $grantType), 7);
|
||||
}
|
||||
|
||||
// Complete the flow
|
||||
return $this->getGrantType($grantType)->completeFlow($inputParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a grant type class
|
||||
* @param string $grantType The grant type identifer
|
||||
* @return Grant\AuthCode|Grant\ClientCredentials|Grant\Implict|Grant\Password|Grant\RefreshToken
|
||||
*/
|
||||
public function getGrantType($grantType)
|
||||
{
|
||||
if (isset($this->grantTypes[$grantType])) {
|
||||
return $this->grantTypes[$grantType];
|
||||
}
|
||||
|
||||
throw new Exception\InvalidGrantTypeException(sprintf(self::$exceptionMessages['unsupported_grant_type'], $grantType), 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a parameter from passed input parameters or the Request class
|
||||
* @param string|array $param Required parameter
|
||||
* @param string $method Get/put/post/delete
|
||||
* @param array $inputParams Passed input parameters
|
||||
* @return mixed 'Null' if parameter is missing
|
||||
*/
|
||||
public function getParam($param = '', $method = 'get', $inputParams = array(), $default = null)
|
||||
{
|
||||
if (is_string($param)) {
|
||||
if (isset($inputParams[$param])) {
|
||||
return $inputParams[$param];
|
||||
} elseif ($param === 'client_id' && ! is_null($clientId = $this->getRequest()->server('PHP_AUTH_USER'))) {
|
||||
return $clientId;
|
||||
} elseif ($param === 'client_secret' && ! is_null($clientSecret = $this->getRequest()->server('PHP_AUTH_PW'))) {
|
||||
return $clientSecret;
|
||||
} else {
|
||||
return $this->getRequest()->{$method}($param, $default);
|
||||
}
|
||||
} else {
|
||||
$response = array();
|
||||
foreach ($param as $p) {
|
||||
$response[$p] = $this->getParam($p, $method, $inputParams);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
20
src/League/OAuth2/Server/Exception/ClientException.php
Normal file
20
src/League/OAuth2/Server/Exception/ClientException.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* ClientException Exception
|
||||
*/
|
||||
class ClientException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Insufficient Scope Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InsufficientScope Exception
|
||||
*/
|
||||
class InsufficientScopeException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Access Token Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InvalidAccessToken Exception
|
||||
*/
|
||||
class InvalidAccessTokenException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Grant Type Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InvalidGrantTypeException Exception
|
||||
*/
|
||||
class InvalidGrantTypeException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Missing Access Token Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* MissingAccessToken Exception
|
||||
*/
|
||||
class MissingAccessTokenException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
20
src/League/OAuth2/Server/Exception/OAuth2Exception.php
Normal file
20
src/League/OAuth2/Server/Exception/OAuth2Exception.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Base Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class OAuth2Exception extends \Exception
|
||||
{
|
||||
|
||||
}
|
259
src/League/OAuth2/Server/Grant/AuthCode.php
Normal file
259
src/League/OAuth2/Server/Grant/AuthCode.php
Normal file
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Auth code grant class
|
||||
*/
|
||||
class AuthCode implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'authorization_code';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = 'code';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* The TTL of the auth token
|
||||
* @var integer
|
||||
*/
|
||||
protected $authTokenTTL = 600;
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $authTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setAuthTokenTTL($authTokenTTL)
|
||||
{
|
||||
$this->authTokenTTL = $authTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check authorise parameters
|
||||
*
|
||||
* @param array $inputParams Optional array of parsed $_GET keys
|
||||
* @throws \OAuth2\Exception\ClientException
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function checkAuthoriseParams($inputParams = array())
|
||||
{
|
||||
// Auth params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'redirect_uri', 'response_type', 'scope', 'state'), 'get', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['redirect_uri'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'redirect_uri'), 0);
|
||||
}
|
||||
|
||||
if ($this->authServer->stateParamRequired() === true && is_null($authParams['state'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'state'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], null, $authParams['redirect_uri'], $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['response_type'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'response_type'), 0);
|
||||
}
|
||||
|
||||
// Ensure response type is one that is recognised
|
||||
if ( ! in_array($authParams['response_type'], $this->authServer->getResponseTypes())) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('unsupported_response_type'), 3);
|
||||
}
|
||||
|
||||
// Validate scopes
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
return $authParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a new authorise request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authParams The authorise request $_GET parameters
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
public function newAuthoriseRequest($type, $typeId, $authParams = array())
|
||||
{
|
||||
// Generate an auth code
|
||||
$authCode = SecureKey::make();
|
||||
|
||||
// Remove any old sessions the user might have
|
||||
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], $type, $typeId);
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], $type, $typeId);
|
||||
|
||||
// Associate a redirect URI
|
||||
$this->authServer->getStorage('session')->associateRedirectUri($sessionId, $authParams['redirect_uri']);
|
||||
|
||||
// Associate the auth code
|
||||
$authCodeId = $this->authServer->getStorage('session')->associateAuthCode($sessionId, $authCode, time() + $this->authTokenTTL);
|
||||
|
||||
// Associate the scopes to the auth code
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateAuthCodeScope($authCodeId, $scope['id']);
|
||||
}
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the auth code grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'redirect_uri', 'code'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['redirect_uri'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'redirect_uri'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], $authParams['redirect_uri'], $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
// Validate the authorization code
|
||||
if (is_null($authParams['code'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'code'), 0);
|
||||
}
|
||||
|
||||
// Verify the authorization code matches the client_id and the request_uri
|
||||
$authCodeDetails = $this->authServer->getStorage('session')->validateAuthCode($authParams['client_id'], $authParams['redirect_uri'], $authParams['code']);
|
||||
|
||||
if ( ! $authCodeDetails) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_grant'), 'code'), 9);
|
||||
}
|
||||
|
||||
// Get any associated scopes
|
||||
$scopes = $this->authServer->getStorage('session')->getAuthCodeScopes($authCodeDetails['authcode_id']);
|
||||
|
||||
// A session ID was returned so update it with an access token and remove the authorisation code
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Remove the auth code
|
||||
$this->authServer->getStorage('session')->removeAuthCode($authCodeDetails['session_id']);
|
||||
|
||||
// Create an access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($authCodeDetails['session_id'], $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
if (count($scopes) > 0) {
|
||||
foreach ($scopes as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['scope_id']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->authServer->hasGrantType('refresh_token')) {
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL();
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']);
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
166
src/League/OAuth2/Server/Grant/ClientCredentials.php
Normal file
166
src/League/OAuth2/Server/Grant/ClientCredentials.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class
|
||||
*/
|
||||
class ClientCredentials implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'client_credentials';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response type
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseType()
|
||||
{
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $accessTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the client credentials grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf(Authorization::getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf(Authorization::getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException(Authorization::getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scope = $this->authServer->getParam('scope', 'post', $inputParams, '');
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $scope);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'client', $authParams['client_id']);
|
||||
|
||||
// Add the access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the new session
|
||||
foreach ($authParams['scopes'] as $scope)
|
||||
{
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
85
src/League/OAuth2/Server/Grant/GrantTrait.php
Normal file
85
src/League/OAuth2/Server/Grant/GrantTrait.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Authorization;
|
||||
|
||||
trait GrantTrait {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param Authorization $authServer Authorization server instance
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Authorization $authServer = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($authServer instanceof Authorization) {
|
||||
trigger_error(
|
||||
'Server is now automatically injected into grant as of v3.1 of this library',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
} // @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @param string $identifier
|
||||
* @return self
|
||||
*/
|
||||
public function setIdentifier($identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response type
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseType()
|
||||
{
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $accessTokenTTL
|
||||
* @return self
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the authorization server into the grant
|
||||
* @param Authorization $authServer The authorization server instance
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthorizationServer(Authorization $authServer)
|
||||
{
|
||||
$this->authServer = $authServer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
48
src/League/OAuth2/Server/Grant/GrantTypeInterface.php
Normal file
48
src/League/OAuth2/Server/Grant/GrantTypeInterface.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Grant type interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
interface GrantTypeInterface
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Authorization $authServer = null);
|
||||
|
||||
/**
|
||||
* Complete the grant flow
|
||||
*
|
||||
* Example response:
|
||||
* <code>
|
||||
* array(
|
||||
* 'access_token' => (string), // The access token
|
||||
* 'refresh_token' => (string), // The refresh token (only set if the refresh token grant is enabled)
|
||||
* 'token_type' => 'bearer', // Almost always "bearer" (exceptions: JWT, SAML)
|
||||
* 'expires' => (int), // The timestamp of when the access token will expire
|
||||
* 'expires_in' => (int) // The number of seconds before the access token will expire
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param null|array $inputParams Null unless the input parameters have been manually set
|
||||
* @return array An array of parameters to be passed back to the client
|
||||
*/
|
||||
public function completeFlow($inputParams = null);
|
||||
}
|
91
src/League/OAuth2/Server/Grant/Implicit.php
Normal file
91
src/League/OAuth2/Server/Grant/Implicit.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 implicit grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class
|
||||
*/
|
||||
class Implicit implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'implicit';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = 'token';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Complete the client credentials grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($authParams = null)
|
||||
{
|
||||
// Remove any old sessions the user might have
|
||||
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], 'user', $authParams['user_id']);
|
||||
|
||||
// Generate a new access token
|
||||
$accessToken = SecureKey::make();
|
||||
|
||||
// Compute expiry time
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $authParams['user_id']);
|
||||
|
||||
// Create an access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn,
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
189
src/League/OAuth2/Server/Grant/Password.php
Normal file
189
src/League/OAuth2/Server/Grant/Password.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Password grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Password grant class
|
||||
*/
|
||||
class Password implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'password';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* Callback to authenticate a user's name and password
|
||||
* @var function
|
||||
*/
|
||||
protected $callback = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Set the callback to verify a user's username and password
|
||||
* @param callable $callback The callback function
|
||||
* @return void
|
||||
*/
|
||||
public function setVerifyCredentialsCallback($callback)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the callback function
|
||||
* @return callable
|
||||
*/
|
||||
protected function getVerifyCredentialsCallback()
|
||||
{
|
||||
if (is_null($this->callback) || ! is_callable($this->callback)) {
|
||||
throw new Exception\InvalidGrantTypeException('Null or non-callable callback set');
|
||||
}
|
||||
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the password grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'username', 'password'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client credentials
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['username'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'username'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['password'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'password'), 0);
|
||||
}
|
||||
|
||||
// Check if user's username and password are correct
|
||||
$userId = call_user_func($this->getVerifyCredentialsCallback(), $authParams['username'], $authParams['password']);
|
||||
|
||||
if ($userId === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_credentials'), 0);
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scope = $this->authServer->getParam('scope', 'post', $inputParams, '');
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $scope);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $userId);
|
||||
|
||||
// Associate an access token with the session
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->authServer->hasGrantType('refresh_token')) {
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL();
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']);
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
207
src/League/OAuth2/Server/Grant/RefreshToken.php
Normal file
207
src/League/OAuth2/Server/Grant/RefreshToken.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Referesh token grant
|
||||
*/
|
||||
class RefreshToken implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'refresh_token';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Refresh token TTL
|
||||
* @var integer
|
||||
*/
|
||||
protected $refreshTokenTTL = 604800;
|
||||
|
||||
/**
|
||||
* Rotate refresh tokens
|
||||
* @var boolean
|
||||
*/
|
||||
protected $rotateRefreshTokens = false;
|
||||
|
||||
/**
|
||||
* Set the TTL of the refresh token
|
||||
* @param int $refreshTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setRefreshTokenTTL($refreshTokenTTL)
|
||||
{
|
||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TTL of the refresh token
|
||||
* @return int
|
||||
*/
|
||||
public function getRefreshTokenTTL()
|
||||
{
|
||||
return $this->refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a new access is token, expire the refresh token used and issue a new one.
|
||||
* @param boolean $rotateRefreshTokens Set to true to enable (default = false)
|
||||
* @return void
|
||||
*/
|
||||
public function rotateRefreshTokens($rotateRefreshTokens = false)
|
||||
{
|
||||
$this->rotateRefreshTokens = $rotateRefreshTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the refresh token grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'refresh_token', 'scope'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['refresh_token'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'refresh_token'), 0);
|
||||
}
|
||||
|
||||
// Validate refresh token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->validateRefreshToken($authParams['refresh_token'], $authParams['client_id']);
|
||||
|
||||
if ($accessTokenId === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_refresh'), 0);
|
||||
}
|
||||
|
||||
// Get the existing access token
|
||||
$accessTokenDetails = $this->authServer->getStorage('session')->getAccessToken($accessTokenId);
|
||||
|
||||
// Get the scopes for the existing access token
|
||||
$scopes = $this->authServer->getStorage('session')->getScopes($accessTokenDetails['access_token']);
|
||||
|
||||
// Generate new tokens and associate them to the session
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Associate the new access token with the session
|
||||
$newAccessTokenId = $this->authServer->getStorage('session')->associateAccessToken($accessTokenDetails['session_id'], $accessToken, $accessTokenExpires);
|
||||
|
||||
if ($this->rotateRefreshTokens === true) {
|
||||
|
||||
// Generate a new refresh token
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenExpires = time() + $this->getRefreshTokenTTL();
|
||||
|
||||
// Revoke the old refresh token
|
||||
$this->authServer->getStorage('session')->removeRefreshToken($authParams['refresh_token']);
|
||||
|
||||
// Associate the new refresh token with the new access token
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']);
|
||||
}
|
||||
|
||||
// There isn't a request for reduced scopes so assign the original ones (or we're not rotating scopes)
|
||||
if ( ! isset($authParams['scope'])) {
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
} elseif ( isset($authParams['scope']) && $this->rotateRefreshTokens === true) {
|
||||
|
||||
// The request is asking for reduced scopes and rotate tokens is enabled
|
||||
$reqestedScopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']);
|
||||
|
||||
for ($i = 0; $i < count($reqestedScopes); $i++) {
|
||||
$reqestedScopes[$i] = trim($reqestedScopes[$i]);
|
||||
if ($reqestedScopes[$i] === '') unset($reqestedScopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
// Check that there aren't any new scopes being included
|
||||
$existingScopes = array();
|
||||
foreach ($scopes as $s) {
|
||||
$existingScopes[] = $s['scope'];
|
||||
}
|
||||
|
||||
foreach ($reqestedScopes as $reqScope) {
|
||||
if ( ! in_array($reqScope, $existingScopes)) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
}
|
||||
|
||||
// Associate with the new access token
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($reqScope, $authParams['client_id'], $this->identifier);
|
||||
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scopeDetails['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
if ($this->rotateRefreshTokens === true) {
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
395
src/League/OAuth2/Server/Resource.php
Normal file
395
src/League/OAuth2/Server/Resource.php
Normal file
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2013-2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Util\RequestInterface;
|
||||
use League\OAuth2\Server\Util\Request;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*/
|
||||
class Resource
|
||||
{
|
||||
/**
|
||||
* The access token
|
||||
* @var string
|
||||
*/
|
||||
protected $accessToken = null;
|
||||
|
||||
/**
|
||||
* The session ID
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionId = null;
|
||||
|
||||
/**
|
||||
* The type of the owner of the access token
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerType = null;
|
||||
|
||||
/**
|
||||
* The ID of the owner of the access token
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerId = null;
|
||||
|
||||
/**
|
||||
* The scopes associated with the access token
|
||||
* @var array
|
||||
*/
|
||||
protected $sessionScopes = array();
|
||||
|
||||
/**
|
||||
* The client, scope and session storage classes
|
||||
* @var array
|
||||
*/
|
||||
protected $storages = array();
|
||||
|
||||
/**
|
||||
* The request object
|
||||
* @var Util\RequestInterface
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* The query string key which is used by clients to present the access token (default: access_token)
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenKey = 'access_token';
|
||||
|
||||
/**
|
||||
* The client ID
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId = null;
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionCodes = array(
|
||||
0 => 'invalid_request',
|
||||
1 => 'invalid_token',
|
||||
2 => 'insufficient_scope',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error messages
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionMessages = array(
|
||||
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
'invalid_token' => 'The access token provided is expired, revoked, malformed, or invalid for other reasons.',
|
||||
'insufficient_scope' => 'The request requires higher privileges than provided by the access token. Required scopes are: %s.',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error HTTP status codes
|
||||
* @var array
|
||||
*
|
||||
* RFC 6750, section 3.1:
|
||||
* When a request fails, the resource server responds using the
|
||||
* appropriate HTTP status code (typically, 400, 401, 403, or 405) and
|
||||
* includes one of the following error codes in the response:
|
||||
*/
|
||||
protected static $exceptionHttpStatusCodes = array(
|
||||
'invalid_request' => 400,
|
||||
'invalid_token' => 401,
|
||||
'insufficient_scope' => 403,
|
||||
);
|
||||
|
||||
/**
|
||||
* Get an exception message
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return string The error message
|
||||
*/
|
||||
public static function getExceptionMessage($error = '')
|
||||
{
|
||||
return self::$exceptionMessages[$error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception code
|
||||
*
|
||||
* @param integer $code The exception code
|
||||
* @return string The exception code type
|
||||
*/
|
||||
public static function getExceptionType($code = 0)
|
||||
{
|
||||
return self::$exceptionCodes[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public static function getExceptionHttpHeaders($error)
|
||||
{
|
||||
$headers = array();
|
||||
switch (self::$exceptionHttpStatusCodes[$error]) {
|
||||
case 401:
|
||||
$headers[] = 'HTTP/1.1 401 Unauthorized';
|
||||
break;
|
||||
case 403:
|
||||
$headers[] = 'HTTP/1.1 403 Forbidden';
|
||||
break;
|
||||
case 400:
|
||||
default:
|
||||
$headers[] = 'HTTP/1.1 400 Bad Request';
|
||||
}
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($error === 'invalid_token') {
|
||||
$authScheme = null;
|
||||
$request = new Request();
|
||||
if ($request->server('PHP_AUTH_USER') !== null) {
|
||||
$authScheme = 'Basic';
|
||||
} else {
|
||||
$authHeader = $request->header('Authorization');
|
||||
if ($authHeader !== null) {
|
||||
if (strpos($authHeader, 'Bearer') === 0) {
|
||||
$authScheme = 'Bearer';
|
||||
} elseif (strpos($authHeader, 'Basic') === 0) {
|
||||
$authScheme = 'Basic';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($authScheme !== null) {
|
||||
$headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""';
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the Resource
|
||||
*
|
||||
* @param SessionInterface The Session Storage Object
|
||||
*/
|
||||
public function __construct(SessionInterface $session)
|
||||
{
|
||||
$this->storages['session'] = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Request Object
|
||||
*
|
||||
* @param RequestInterface The Request Object
|
||||
*/
|
||||
public function setRequest(RequestInterface $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Request object. It will create one from the globals if one is not set.
|
||||
*
|
||||
* @return Util\RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->request = Request::buildFromGlobals();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query string key for the access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTokenKey()
|
||||
{
|
||||
return $this->tokenKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query string key for the access token.
|
||||
*
|
||||
* @param $key The new query string key
|
||||
*/
|
||||
public function setTokenKey($key)
|
||||
{
|
||||
$this->tokenKey = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the access token owner ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerId()
|
||||
{
|
||||
return $this->ownerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the owner type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerType()
|
||||
{
|
||||
return $this->ownerType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client ID that created the session
|
||||
* @return string
|
||||
*/
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the access token is valid or not.
|
||||
*
|
||||
* @param $headersOnly Limit Access Token to Authorization header only
|
||||
* @throws Exception\InvalidAccessTokenException Thrown if the presented access token is not valid
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($headersOnly = false)
|
||||
{
|
||||
$accessToken = $this->determineAccessToken($headersOnly);
|
||||
|
||||
$result = $this->storages['session']->validateAccessToken($accessToken);
|
||||
|
||||
if (! $result) {
|
||||
throw new Exception\InvalidAccessTokenException(self::$exceptionMessages['invalid_token'], 1);
|
||||
}
|
||||
|
||||
$this->accessToken = $accessToken;
|
||||
$this->sessionId = $result['session_id'];
|
||||
$this->clientId = $result['client_id'];
|
||||
$this->ownerType = $result['owner_type'];
|
||||
$this->ownerId = $result['owner_id'];
|
||||
|
||||
$sessionScopes = $this->storages['session']->getScopes($this->accessToken);
|
||||
foreach ($sessionScopes as $scope) {
|
||||
$this->sessionScopes[] = $scope['scope'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session scopes
|
||||
* @return array
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return $this->sessionScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the presented access token has the given scope(s).
|
||||
*
|
||||
* @param array|string An array of scopes or a single scope as a string
|
||||
* @param bool If scopes are required, missing scope will trigger an exception
|
||||
* @throws Exception\InsufficientScopeException Thrown if the any of the given scopes are not in the session
|
||||
* @return bool Returns bool if all scopes are found, false if any fail
|
||||
*/
|
||||
public function hasScope($scopes, $required = false)
|
||||
{
|
||||
if (!is_array($scopes)) {
|
||||
$scopes = array($scopes);
|
||||
}
|
||||
|
||||
$missing = array_diff($scopes, $this->sessionScopes);
|
||||
|
||||
if ($missing) {
|
||||
if ($required) {
|
||||
$missing = implode(', ', $missing);
|
||||
throw new Exception\InsufficientScopeException(sprintf(self::$exceptionMessages['insufficient_scope'], $missing), 3);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the access token from the headers.
|
||||
*
|
||||
* @param $headersOnly Limit Access Token to Authorization header only
|
||||
* @throws Exception\MissingAccessTokenException Thrown if there is no access token presented
|
||||
* @return string
|
||||
*/
|
||||
public function determineAccessToken($headersOnly = false)
|
||||
{
|
||||
// Try to get it directly from a header
|
||||
if (! $header = $this->getRequest()->header('Authorization')) {
|
||||
|
||||
// Failing that try getting it from a server variable
|
||||
$header = $this->getRequest()->server('HTTP_AUTHORIZATION');
|
||||
}
|
||||
|
||||
// One of them worked
|
||||
if ($header) {
|
||||
// Check for special case, because cURL sometimes does an
|
||||
// internal second request and doubles the authorization header,
|
||||
// which always resulted in an error.
|
||||
//
|
||||
// 1st request: Authorization: Bearer XXX
|
||||
// 2nd request: Authorization: Bearer XXX, Bearer XXX
|
||||
if (strpos($header, ',') !== false) {
|
||||
$headerPart = explode(',', $header);
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $headerPart[0]));
|
||||
} else {
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header));
|
||||
}
|
||||
$accessToken = ($accessToken === 'Bearer') ? '' : $accessToken;
|
||||
} elseif ($headersOnly === false) {
|
||||
$method = $this->getRequest()->server('REQUEST_METHOD');
|
||||
$accessToken = $this->getRequest()->{$method}($this->tokenKey);
|
||||
}
|
||||
|
||||
if (empty($accessToken)) {
|
||||
throw new Exception\MissingAccessTokenException(self::$exceptionMessages['invalid_request'], 0);
|
||||
}
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
}
|
60
src/League/OAuth2/Server/Storage/ClientInterface.php
Normal file
60
src/League/OAuth2/Server/Storage/ClientInterface.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface ClientInterface
|
||||
{
|
||||
/**
|
||||
* Validate a client
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* # Client ID + redirect URI
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_client_endpoints.redirect_uri, oauth_clients.name,
|
||||
* oauth_clients.auto_approve
|
||||
* FROM oauth_clients LEFT JOIN oauth_client_endpoints ON oauth_client_endpoints.client_id = oauth_clients.id
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_client_endpoints.redirect_uri = :redirectUri
|
||||
*
|
||||
* # Client ID + client secret
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_clients.name, oauth_clients.auto_approve FROM oauth_clients
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_clients.secret = :clientSecret
|
||||
*
|
||||
* # Client ID + client secret + redirect URI
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_client_endpoints.redirect_uri, oauth_clients.name,
|
||||
* oauth_clients.auto_approve FROM oauth_clients LEFT JOIN oauth_client_endpoints
|
||||
* ON oauth_client_endpoints.client_id = oauth_clients.id
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_clients.secret = :clientSecret AND
|
||||
* oauth_client_endpoints.redirect_uri = :redirectUri
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [client_id] => (string) The client ID
|
||||
* [client secret] => (string) The client secret
|
||||
* [redirect_uri] => (string) The redirect URI used in this request
|
||||
* [name] => (string) The name of the client
|
||||
* [auto_approve] => (bool) Whether the client should auto approve
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client's ID
|
||||
* @param string $clientSecret The client's secret (default = "null")
|
||||
* @param string $redirectUri The client's redirect URI (default = "null")
|
||||
* @param string $grantType The grant type used in the request (default = "null")
|
||||
* @return bool|array Returns false if the validation fails, array on success
|
||||
*/
|
||||
public function getClient($clientId, $clientSecret = null, $redirectUri = null, $grantType = null);
|
||||
}
|
43
src/League/OAuth2/Server/Storage/ScopeInterface.php
Normal file
43
src/League/OAuth2/Server/Storage/ScopeInterface.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Scope storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface ScopeInterface
|
||||
{
|
||||
/**
|
||||
* Return information about a scope
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM oauth_scopes WHERE scope = :scope
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The scope's ID
|
||||
* [scope] => (string) The scope itself
|
||||
* [name] => (string) The scope's name
|
||||
* [description] => (string) The scope's description
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $scope The scope
|
||||
* @param string $clientId The client ID (default = "null")
|
||||
* @param string $grantType The grant type used in the request (default = "null")
|
||||
* @return bool|array If the scope doesn't exist return false
|
||||
*/
|
||||
public function getScope($scope, $clientId = null, $grantType = null);
|
||||
}
|
332
src/League/OAuth2/Server/Storage/SessionInterface.php
Normal file
332
src/League/OAuth2/Server/Storage/SessionInterface.php
Normal file
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Session storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface SessionInterface
|
||||
{
|
||||
/**
|
||||
* Create a new session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_sessions (client_id, owner_type, owner_id)
|
||||
* VALUE (:clientId, :ownerType, :ownerId)
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $ownerType The type of the session owner (e.g. "user")
|
||||
* @param string $ownerId The ID of the session owner (e.g. "123")
|
||||
* @return int The session ID
|
||||
*/
|
||||
public function createSession($clientId, $ownerType, $ownerId);
|
||||
|
||||
/**
|
||||
* Delete a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM oauth_sessions WHERE client_id = :clientId AND owner_type = :type AND owner_id = :typeId
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $ownerType The type of the session owner (e.g. "user")
|
||||
* @param string $ownerId The ID of the session owner (e.g. "123")
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSession($clientId, $ownerType, $ownerId);
|
||||
|
||||
/**
|
||||
* Associate a redirect URI with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_redirects (session_id, redirect_uri) VALUE (:sessionId, :redirectUri)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @return void
|
||||
*/
|
||||
public function associateRedirectUri($sessionId, $redirectUri);
|
||||
|
||||
/**
|
||||
* Associate an access token with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_access_tokens (session_id, access_token, access_token_expires)
|
||||
* VALUE (:sessionId, :accessToken, :accessTokenExpire)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $accessToken The access token
|
||||
* @param int $expireTime Unix timestamp of the access token expiry time
|
||||
* @return int The access token ID
|
||||
*/
|
||||
public function associateAccessToken($sessionId, $accessToken, $expireTime);
|
||||
|
||||
/**
|
||||
* Associate a refresh token with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_refresh_tokens (session_access_token_id, refresh_token, refresh_token_expires,
|
||||
* client_id) VALUE (:accessTokenId, :refreshToken, :expireTime, :clientId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The access token ID
|
||||
* @param string $refreshToken The refresh token
|
||||
* @param int $expireTime Unix timestamp of the refresh token expiry time
|
||||
* @param string $clientId The client ID
|
||||
* @return void
|
||||
*/
|
||||
public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime, $clientId);
|
||||
|
||||
/**
|
||||
* Assocate an authorization code with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires)
|
||||
* VALUE (:sessionId, :authCode, :authCodeExpires)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $authCode The authorization code
|
||||
* @param int $expireTime Unix timestamp of the access token expiry time
|
||||
* @return int The auth code ID
|
||||
*/
|
||||
public function associateAuthCode($sessionId, $authCode, $expireTime);
|
||||
|
||||
/**
|
||||
* Remove an associated authorization token from a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM oauth_session_authcodes WHERE session_id = :sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @return void
|
||||
*/
|
||||
public function removeAuthCode($sessionId);
|
||||
|
||||
/**
|
||||
* Validate an authorization code
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT oauth_sessions.id AS session_id, oauth_session_authcodes.id AS authcode_id FROM oauth_sessions
|
||||
* JOIN oauth_session_authcodes ON oauth_session_authcodes.`session_id` = oauth_sessions.id
|
||||
* JOIN oauth_session_redirects ON oauth_session_redirects.`session_id` = oauth_sessions.id WHERE
|
||||
* oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code` = :authCode
|
||||
* AND `oauth_session_authcodes`.`auth_code_expires` >= :time AND
|
||||
* `oauth_session_redirects`.`redirect_uri` = :redirectUri
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'session_id' => (int)
|
||||
* 'authcode_id' => (int)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $authCode The authorization code
|
||||
* @return array|bool False if invalid or array as above
|
||||
*/
|
||||
public function validateAuthCode($clientId, $redirectUri, $authCode);
|
||||
|
||||
/**
|
||||
* Validate an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT session_id, oauth_sessions.`client_id`, oauth_sessions.`owner_id`, oauth_sessions.`owner_type`
|
||||
* FROM `oauth_session_access_tokens` JOIN oauth_sessions ON oauth_sessions.`id` = session_id WHERE
|
||||
* access_token = :accessToken AND access_token_expires >= UNIX_TIMESTAMP(NOW())
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'session_id' => (int),
|
||||
* 'client_id' => (string),
|
||||
* 'owner_id' => (string),
|
||||
* 'owner_type' => (string)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array|bool False if invalid or an array as above
|
||||
*/
|
||||
public function validateAccessToken($accessToken);
|
||||
|
||||
/**
|
||||
* Removes a refresh token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken
|
||||
* </code>
|
||||
*
|
||||
* @param string $refreshToken The refresh token to be removed
|
||||
* @return void
|
||||
*/
|
||||
public function removeRefreshToken($refreshToken);
|
||||
|
||||
/**
|
||||
* Validate a refresh token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT session_access_token_id FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken
|
||||
* AND refresh_token_expires >= UNIX_TIMESTAMP(NOW()) AND client_id = :clientId
|
||||
* </code>
|
||||
*
|
||||
* @param string $refreshToken The refresh token
|
||||
* @param string $clientId The client ID
|
||||
* @return int|bool The ID of the access token the refresh token is linked to (or false if invalid)
|
||||
*/
|
||||
public function validateRefreshToken($refreshToken, $clientId);
|
||||
|
||||
/**
|
||||
* Get an access token by ID
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM `oauth_session_access_tokens` WHERE `id` = :accessTokenId
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'id' => (int),
|
||||
* 'session_id' => (int),
|
||||
* 'access_token' => (string),
|
||||
* 'access_token_expires' => (int)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The access token ID
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($accessTokenId);
|
||||
|
||||
/**
|
||||
* Associate scopes with an auth code (bound to the session)
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO `oauth_session_authcode_scopes` (`oauth_session_authcode_id`, `scope_id`) VALUES
|
||||
* (:authCodeId, :scopeId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $authCodeId The auth code ID
|
||||
* @param int $scopeId The scope ID
|
||||
* @return void
|
||||
*/
|
||||
public function associateAuthCodeScope($authCodeId, $scopeId);
|
||||
|
||||
/**
|
||||
* Get the scopes associated with an auth code
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT scope_id FROM `oauth_session_authcode_scopes` WHERE oauth_session_authcode_id = :authCodeId
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* array(
|
||||
* 'scope_id' => (int)
|
||||
* ),
|
||||
* array(
|
||||
* 'scope_id' => (int)
|
||||
* ),
|
||||
* ...
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param int $oauthSessionAuthCodeId The session ID
|
||||
* @return array
|
||||
*/
|
||||
public function getAuthCodeScopes($oauthSessionAuthCodeId);
|
||||
|
||||
/**
|
||||
* Associate a scope with an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO `oauth_session_token_scopes` (`session_access_token_id`, `scope_id`) VALUE (:accessTokenId, :scopeId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The ID of the access token
|
||||
* @param int $scopeId The ID of the scope
|
||||
* @return void
|
||||
*/
|
||||
public function associateScope($accessTokenId, $scopeId);
|
||||
|
||||
/**
|
||||
* Get all associated access tokens for an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT oauth_scopes.* FROM oauth_session_token_scopes JOIN oauth_session_access_tokens
|
||||
* ON oauth_session_access_tokens.`id` = `oauth_session_token_scopes`.`session_access_token_id`
|
||||
* JOIN oauth_scopes ON oauth_scopes.id = `oauth_session_token_scopes`.`scope_id`
|
||||
* WHERE access_token = :accessToken
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array (
|
||||
* array(
|
||||
* 'id' => (int),
|
||||
* 'scope' => (string),
|
||||
* 'name' => (string),
|
||||
* 'description' => (string)
|
||||
* ),
|
||||
* ...
|
||||
* ...
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array
|
||||
*/
|
||||
public function getScopes($accessToken);
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key default algorithm
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util\KeyAlgorithm;
|
||||
|
||||
|
||||
class DefaultAlgorithm implements KeyAlgorithmInterface
|
||||
{
|
||||
/**
|
||||
* @param int $len
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function make($len = 40)
|
||||
{
|
||||
// We generate twice as many bytes here because we want to ensure we have
|
||||
// enough after we base64 encode it to get the length we need because we
|
||||
// take out the "/", "+", and "=" characters.
|
||||
$bytes = openssl_random_pseudo_bytes($len * 2, $strong);
|
||||
|
||||
// We want to stop execution if the key fails because, well, that is bad.
|
||||
if ($bytes === false || $strong === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Exception('Error Generating Key');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $len);
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Key algorithm interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util\KeyAlgorithm;
|
||||
|
||||
|
||||
interface KeyAlgorithmInterface
|
||||
{
|
||||
public function make($len = 40);
|
||||
}
|
31
src/League/OAuth2/Server/Util/RedirectUri.php
Normal file
31
src/League/OAuth2/Server/Util/RedirectUri.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Redirect URI generator
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
/**
|
||||
* RedirectUri class
|
||||
*/
|
||||
class RedirectUri
|
||||
{
|
||||
/**
|
||||
* Generate a new redirect uri
|
||||
* @param string $uri The base URI
|
||||
* @param array $params The query string parameters
|
||||
* @param string $queryDelimeter The query string delimeter (default: "?")
|
||||
* @return string The updated URI
|
||||
*/
|
||||
public static function make($uri, $params = array(), $queryDelimeter = '?')
|
||||
{
|
||||
$uri .= (strstr($uri, $queryDelimeter) === false) ? $queryDelimeter : '&';
|
||||
return $uri.http_build_query($params);
|
||||
}
|
||||
}
|
146
src/League/OAuth2/Server/Util/Request.php
Normal file
146
src/League/OAuth2/Server/Util/Request.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Request class
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use InvalidMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
protected $get = array();
|
||||
protected $post = array();
|
||||
protected $cookies = array();
|
||||
protected $files = array();
|
||||
protected $server = array();
|
||||
protected $headers = array();
|
||||
|
||||
public static function buildFromGlobals()
|
||||
{
|
||||
return new static($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
}
|
||||
|
||||
public function __construct(array $get = array(), array $post = array(), array $cookies = array(), array $files = array(), array $server = array(), $headers = array())
|
||||
{
|
||||
$this->get = $get;
|
||||
$this->post = $post;
|
||||
$this->cookies = $cookies;
|
||||
$this->files = $files;
|
||||
$this->server = $server;
|
||||
|
||||
if (empty($headers)) {
|
||||
$this->headers = $this->readHeaders();
|
||||
} else {
|
||||
$this->headers = $this->normalizeHeaders($headers);
|
||||
}
|
||||
}
|
||||
|
||||
public function get($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('get', $index, $default);
|
||||
}
|
||||
|
||||
public function post($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('post', $index, $default);
|
||||
}
|
||||
|
||||
public function file($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('files', $index, $default);
|
||||
}
|
||||
|
||||
public function cookie($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('cookies', $index, $default);
|
||||
}
|
||||
|
||||
public function server($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('server', $index, $default);
|
||||
}
|
||||
|
||||
public function header($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('headers', $index, $default);
|
||||
}
|
||||
|
||||
protected function readHeaders()
|
||||
{
|
||||
if (function_exists('getallheaders')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$headers = getallheaders();
|
||||
} else {
|
||||
// @codeCoverageIgnoreEnd
|
||||
$headers = array();
|
||||
foreach ($this->server() as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
|
||||
$headers[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->normalizeHeaders($headers);
|
||||
}
|
||||
|
||||
protected function getPropertyValue($property, $index = null, $default = null)
|
||||
{
|
||||
if ( ! isset($this->{$property})) {
|
||||
throw new InvalidArgumentException("Property '$property' does not exist.");
|
||||
}
|
||||
if (is_null($index)) {
|
||||
return $this->{$property};
|
||||
}
|
||||
|
||||
if ( ! array_key_exists($index, $this->{$property})) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->{$property}[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes all of the headers and normalizes them in a canonical form.
|
||||
*
|
||||
* @param array $headers The request headers.
|
||||
* @return array An arry of headers with the header name normalized
|
||||
*/
|
||||
protected function normalizeHeaders(array $headers)
|
||||
{
|
||||
$normalized = array();
|
||||
foreach ($headers as $key => $value) {
|
||||
$normalized[ucfirst($this->normalizeKey($key))] = $value;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform header name into canonical form
|
||||
*
|
||||
* Taken from the Slim codebase...
|
||||
*
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeKey($key)
|
||||
{
|
||||
$key = strtolower($key);
|
||||
$key = str_replace(array('-', '_'), ' ', $key);
|
||||
$key = preg_replace('#^http #', '', $key);
|
||||
$key = ucwords($key);
|
||||
$key = str_replace(' ', '-', $key);
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
29
src/League/OAuth2/Server/Util/RequestInterface.php
Normal file
29
src/League/OAuth2/Server/Util/RequestInterface.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Request class interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
interface RequestInterface
|
||||
{
|
||||
|
||||
public function get($index = null);
|
||||
|
||||
public function post($index = null);
|
||||
|
||||
public function cookie($index = null);
|
||||
|
||||
public function file($index = null);
|
||||
|
||||
public function server($index = null);
|
||||
|
||||
public function header($index = null);
|
||||
|
||||
}
|
54
src/League/OAuth2/Server/Util/SecureKey.php
Normal file
54
src/League/OAuth2/Server/Util/SecureKey.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key generator
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
use League\OAuth2\Server\Util\KeyAlgorithm\DefaultAlgorithm;
|
||||
use League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface;
|
||||
|
||||
/**
|
||||
* SecureKey class
|
||||
*/
|
||||
class SecureKey
|
||||
{
|
||||
protected static $algorithm;
|
||||
|
||||
/**
|
||||
* Generate a new unique code
|
||||
* @param integer $len Length of the generated code
|
||||
* @return string
|
||||
*/
|
||||
public static function make($len = 40)
|
||||
{
|
||||
return self::getAlgorithm()->make($len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param KeyAlgorithmInterface $algorithm
|
||||
*/
|
||||
public static function setAlgorithm(KeyAlgorithmInterface $algorithm)
|
||||
{
|
||||
self::$algorithm = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return KeyAlgorithmInterface
|
||||
*/
|
||||
public static function getAlgorithm()
|
||||
{
|
||||
if (!self::$algorithm) {
|
||||
|
||||
self::$algorithm = new DefaultAlgorithm();
|
||||
}
|
||||
|
||||
return self::$algorithm;
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
<?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 Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthorizationServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var AuthorizationServer
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* @param AuthorizationServer $server
|
||||
*/
|
||||
public function __construct(AuthorizationServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param callable $next
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
|
||||
{
|
||||
try {
|
||||
$response = $this->server->respondToAccessTokenRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
|
||||
->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// Pass the request and response on to the next responder in the chain
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
<?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\ResourceServer;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ResourceServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var ResourceServer
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* @param ResourceServer $server
|
||||
*/
|
||||
public function __construct(ResourceServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param callable $next
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
|
||||
{
|
||||
try {
|
||||
$request = $this->server->validateAuthenticatedRequest($request);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500))
|
||||
->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// Pass the request and response on to the next responder in the chain
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
/**
|
||||
* Access token interface.
|
||||
*/
|
||||
interface AccessTokenRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new access token
|
||||
*
|
||||
* @param ClientEntityInterface $clientEntity
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
* @param mixed $userIdentifier
|
||||
*
|
||||
* @return AccessTokenEntityInterface
|
||||
*/
|
||||
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null);
|
||||
|
||||
/**
|
||||
* Persists a new access token to permanent storage.
|
||||
*
|
||||
* @param AccessTokenEntityInterface $accessTokenEntity
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity);
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeAccessToken($tokenId);
|
||||
|
||||
/**
|
||||
* Check if the access token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId);
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
|
||||
/**
|
||||
* Auth code storage interface.
|
||||
*/
|
||||
interface AuthCodeRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates a new AuthCode
|
||||
*
|
||||
* @return AuthCodeEntityInterface
|
||||
*/
|
||||
public function getNewAuthCode();
|
||||
|
||||
/**
|
||||
* Persists a new auth code to permanent storage.
|
||||
*
|
||||
* @param AuthCodeEntityInterface $authCodeEntity
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
|
||||
|
||||
/**
|
||||
* Revoke an auth code.
|
||||
*
|
||||
* @param string $codeId
|
||||
*/
|
||||
public function revokeAuthCode($codeId);
|
||||
|
||||
/**
|
||||
* Check if the auth code has been revoked.
|
||||
*
|
||||
* @param string $codeId
|
||||
*
|
||||
* @return bool Return true if this code has been revoked
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId);
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
|
||||
/**
|
||||
* Client storage interface.
|
||||
*/
|
||||
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 bool $mustValidateSecret If true the client must attempt to validate the secret if the client
|
||||
* is confidential
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true);
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
|
||||
/**
|
||||
* Refresh token interface.
|
||||
*/
|
||||
interface RefreshTokenRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates a new refresh token
|
||||
*
|
||||
* @return RefreshTokenEntityInterface
|
||||
*/
|
||||
public function getNewRefreshToken();
|
||||
|
||||
/**
|
||||
* Create a new refresh token_name.
|
||||
*
|
||||
* @param RefreshTokenEntityInterface $refreshTokenEntity
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity);
|
||||
|
||||
/**
|
||||
* Revoke the refresh token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId);
|
||||
|
||||
/**
|
||||
* Check if the refresh token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId);
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Repository interface.
|
||||
*/
|
||||
interface RepositoryInterface
|
||||
{
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
|
||||
/**
|
||||
* Scope interface.
|
||||
*/
|
||||
interface ScopeRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return information about a scope.
|
||||
*
|
||||
* @param string $identifier The scope identifier
|
||||
*
|
||||
* @return ScopeEntityInterface
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally
|
||||
* append additional scopes or remove requested scopes.
|
||||
*
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
* @param string $grantType
|
||||
* @param ClientEntityInterface $clientEntity
|
||||
* @param null|string $userIdentifier
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity,
|
||||
$userIdentifier = null
|
||||
);
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
|
||||
interface UserRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get a user entity.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $grantType The grant type used
|
||||
* @param ClientEntityInterface $clientEntity
|
||||
*
|
||||
* @return UserEntityInterface
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity
|
||||
);
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
<?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;
|
||||
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 ServerRequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* RequestEvent constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function __construct($name, ServerRequestInterface $request)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ServerRequestInterface
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
@@ -1,224 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
|
||||
class AuthorizationRequest
|
||||
{
|
||||
/**
|
||||
* The grant type identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $grantTypeId;
|
||||
|
||||
/**
|
||||
* The client identifier
|
||||
*
|
||||
* @var ClientEntityInterface
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* The user identifier
|
||||
*
|
||||
* @var UserEntityInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* An array of scope identifiers
|
||||
*
|
||||
* @var ScopeEntityInterface[]
|
||||
*/
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* Has the user authorized the authorization request
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $authorizationApproved = false;
|
||||
|
||||
/**
|
||||
* The redirect URI used in the request
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectUri;
|
||||
|
||||
/**
|
||||
* The state parameter on the authorization request
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The code challenge (if provided)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $codeChallenge;
|
||||
|
||||
/**
|
||||
* The code challenge method (if provided)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $codeChallengeMethod;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getGrantTypeId()
|
||||
{
|
||||
return $this->grantTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $grantTypeId
|
||||
*/
|
||||
public function setGrantTypeId($grantTypeId)
|
||||
{
|
||||
$this->grantTypeId = $grantTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClientEntityInterface $client
|
||||
*/
|
||||
public function setClient(ClientEntityInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UserEntityInterface
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserEntityInterface $user
|
||||
*/
|
||||
public function setUser(UserEntityInterface $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
*/
|
||||
public function setScopes(array $scopes)
|
||||
{
|
||||
$this->scopes = $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuthorizationApproved()
|
||||
{
|
||||
return $this->authorizationApproved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $authorizationApproved
|
||||
*/
|
||||
public function setAuthorizationApproved($authorizationApproved)
|
||||
{
|
||||
$this->authorizationApproved = $authorizationApproved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirectUri
|
||||
*/
|
||||
public function setRedirectUri($redirectUri)
|
||||
{
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*/
|
||||
public function setState($state)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
<?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\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ResourceServer
|
||||
{
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var CryptKey
|
||||
*/
|
||||
private $publicKey;
|
||||
|
||||
/**
|
||||
* @var null|AuthorizationValidatorInterface
|
||||
*/
|
||||
private $authorizationValidator;
|
||||
|
||||
/**
|
||||
* New server instance.
|
||||
*
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param CryptKey|string $publicKey
|
||||
* @param null|AuthorizationValidatorInterface $authorizationValidator
|
||||
*/
|
||||
public function __construct(
|
||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||
$publicKey,
|
||||
AuthorizationValidatorInterface $authorizationValidator = null
|
||||
) {
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
|
||||
if ($publicKey instanceof CryptKey === false) {
|
||||
$publicKey = new CryptKey($publicKey);
|
||||
}
|
||||
$this->publicKey = $publicKey;
|
||||
|
||||
$this->authorizationValidator = $authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AuthorizationValidatorInterface
|
||||
*/
|
||||
protected function getAuthorizationValidator()
|
||||
{
|
||||
if ($this->authorizationValidator instanceof AuthorizationValidatorInterface === false) {
|
||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||
}
|
||||
|
||||
$this->authorizationValidator->setPublicKey($this->publicKey);
|
||||
|
||||
return $this->authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token validity.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @throws OAuthServerException
|
||||
*
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthenticatedRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->getAuthorizationValidator()->validateAuthorization($request);
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract Response Type.
|
||||
*
|
||||
* @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\ResponseTypes;
|
||||
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
|
||||
abstract class AbstractResponseType implements ResponseTypeInterface
|
||||
{
|
||||
use CryptTrait;
|
||||
|
||||
/**
|
||||
* @var AccessTokenEntityInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @var RefreshTokenEntityInterface
|
||||
*/
|
||||
protected $refreshToken;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRefreshToken(RefreshTokenEntityInterface $refreshToken)
|
||||
{
|
||||
$this->refreshToken = $refreshToken;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user