add oauth2/oidc lib
This commit is contained in:
		
							
								
								
									
										5
									
								
								library/oauth2/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								library/oauth2/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # Test Files # | ||||||
|  | test/config/test.sqlite | ||||||
|  | vendor | ||||||
|  | composer.lock | ||||||
|  | .idea | ||||||
							
								
								
									
										30
									
								
								library/oauth2/.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								library/oauth2/.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | language: php | ||||||
|  | sudo: false | ||||||
|  | cache: | ||||||
|  |   directories: | ||||||
|  |     - $HOME/.composer/cache | ||||||
|  |     - vendor | ||||||
|  | php: | ||||||
|  | - 5.3 | ||||||
|  | - 5.4 | ||||||
|  | - 5.5 | ||||||
|  | - 5.6 | ||||||
|  | - 7 | ||||||
|  | - hhvm | ||||||
|  | env: | ||||||
|  |   global: | ||||||
|  |   - SKIP_MONGO_TESTS=1 | ||||||
|  |   - secure: Bc5ZqvZ1YYpoPZNNuU2eCB8DS6vBYrAdfBtTenBs5NSxzb+Vjven4kWakbzaMvZjb/Ib7Uph7DGuOtJXpmxnvBXPLd707LZ89oFWN/yqQlZKCcm8iErvJCB5XL+/ONHj2iPdR242HJweMcat6bMCwbVWoNDidjtWMH0U2mYFy3M= | ||||||
|  |   - secure: R3bXlymyFiY2k2jf7+fv/J8i34wtXTkmD4mCr5Ps/U+vn9axm2VtvR2Nj+r7LbRjn61gzFE/xIVjYft/wOyBOYwysrfriydrnRVS0owh6y+7EyOyQWbRX11vVQMf8o31QCQE5BY58V5AJZW3MjoOL0FVlTgySJiJvdw6Pv18v+E= | ||||||
|  | services: | ||||||
|  | - mongodb | ||||||
|  | - redis-server | ||||||
|  | - cassandra | ||||||
|  | before_install: | ||||||
|  | - phpenv config-rm xdebug.ini || return 0 | ||||||
|  | install: | ||||||
|  | - composer install --no-interaction | ||||||
|  | before_script: | ||||||
|  | - psql -c 'create database oauth2_server_php;' -U postgres | ||||||
|  | after_script: | ||||||
|  | - php test/cleanup.php | ||||||
							
								
								
									
										152
									
								
								library/oauth2/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								library/oauth2/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | CHANGELOG for 1.x | ||||||
|  | ================= | ||||||
|  |  | ||||||
|  | This changelog references the relevant changes (bug and security fixes) done | ||||||
|  | in 1.x minor versions. | ||||||
|  |  | ||||||
|  | To see the files changed for a given bug, go to https://github.com/bshaffer/oauth2-server-php/issues/### where ### is the bug number | ||||||
|  | To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1 | ||||||
|  | To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash | ||||||
|  |  | ||||||
|  | * 1.8.0 (2015-09-18) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/643 | ||||||
|  |  | ||||||
|  |   * bug #594 - adds jti | ||||||
|  |   * bug #598 - fixes lifetime configurations for JWTs | ||||||
|  |   * bug #634 - fixes travis builds, upgrade to containers | ||||||
|  |   * bug #586 - support for revoking tokens | ||||||
|  |   * bug #636 - Adds FirebaseJWT bridge | ||||||
|  |   * bug #639 - Mongo HHVM compatibility | ||||||
|  |  | ||||||
|  | * 1.7.0 (2015-04-23) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/572 | ||||||
|  |  | ||||||
|  |   * bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC | ||||||
|  |   * bug #508 - Case insensitive for Bearer token header name  ba716d4 | ||||||
|  |   * bug #512 - validateRedirectUri is now public | ||||||
|  |   * bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage | ||||||
|  |   * bug #505 - DynamoDB storage fixes | ||||||
|  |   * bug #556 - adds "code id_token" return type to openid connect | ||||||
|  |   * bug #563 - Include "issuer" config key for JwtAccessToken | ||||||
|  |   * bug #564 - Fixes JWT vulnerability | ||||||
|  |   * bug #571 - Added unset_refresh_token_after_use option | ||||||
|  |  | ||||||
|  | * 1.6 (2015-01-16) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/496 | ||||||
|  |  | ||||||
|  |   * bug 437 - renames CryptoToken to JwtAccessToken / use_crypto_tokens to use_jwt_access_tokens | ||||||
|  |   * bug 447 - Adds a Couchbase storage implementation | ||||||
|  |   * bug 460 - Rename JWT claims to match spec | ||||||
|  |   * bug 470 - order does not matter for multi-valued response types | ||||||
|  |   * bug 471 - Make validateAuthorizeRequest available for POST in addition to GET | ||||||
|  |   * bug 475 - Adds JTI table definitiion | ||||||
|  |   * bug 481 - better randomness for generating access tokens | ||||||
|  |   * bug 480 - Use hash_equals() for signature verification (prevents remote timing attacks) | ||||||
|  |   * bugs 489, 491, 498 - misc other fixes | ||||||
|  |  | ||||||
|  | * 1.5 (2014-08-27) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/446 | ||||||
|  |  | ||||||
|  |   * bug #399 - Add DynamoDB Support | ||||||
|  |   * bug #404 - renamed error name for malformed/expired tokens | ||||||
|  |   * bug #412 - Openid connect: fixes for claims with more than one scope / Add support for the prompt parameter ('consent' and 'none') | ||||||
|  |   * bug #411 - fixes xml output | ||||||
|  |   * bug #413 - fixes invalid format error | ||||||
|  |   * bug #401 - fixes code standards / whitespace | ||||||
|  |   * bug #354 - bundles PDO SQL with the library | ||||||
|  |   * [BC] bug #397 - refresh tokens should not be encrypted | ||||||
|  |   * bug #423 - makes "scope" optional for refresh token storage | ||||||
|  |  | ||||||
|  | * 1.4 (2014-06-12) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/392 | ||||||
|  |  | ||||||
|  |   * bug #189 Storage\PDO - allows DSN string in constructor | ||||||
|  |   * bug #233 Bearer Tokens - allows token in request body for PUT requests | ||||||
|  |   * bug #346 Fixes open_basedir warning | ||||||
|  |   * bug #351 Adds OpenID Connect support | ||||||
|  |   * bug #355 Adds php 5.6 and HHVM to travis.ci testing | ||||||
|  |   * [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface | ||||||
|  |   * bug #363 Encryption\JWT - Allows for subclassing JWT Headers | ||||||
|  |   * bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional | ||||||
|  |   * bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected | ||||||
|  |   * bug #323 ResourceController - client_id is no longer required to be returned when calling getAccessToken | ||||||
|  |   * bug #367 Storage\PDO - adds Postgres support | ||||||
|  |   * bug #368 Access Tokens - use mcrypt_create_iv or openssl_random_pseudo_bytes to create token string | ||||||
|  |   * bug #376 Request - allows case insensitive headers | ||||||
|  |   * bug #384 Storage\PDO - can pass in PDO options in constructor of PDO storage | ||||||
|  |   * misc fixes #361, #292, #373, #374, #379, #396 | ||||||
|  | * 1.3 (2014-02-27) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/325 | ||||||
|  |  | ||||||
|  |   * bug #311 adds cassandra storage | ||||||
|  |   * bug #298 fixes response code for user credentials grant type | ||||||
|  |   * bug #318 adds 'use_crypto_tokens' config to Server class for better DX | ||||||
|  |   * [BC] bug #320 pass client_id to getDefaultScope | ||||||
|  |   * bug #324 better feedback when running tests | ||||||
|  |   * bug #335 adds support for non-expiring refresh tokens | ||||||
|  |   * bug #333 fixes Pdo storage for getClientKey | ||||||
|  |   * bug #336 fixes Redis storage for expireAuthorizationCode | ||||||
|  |  | ||||||
|  | * 1.2 (2014-01-03) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/288 | ||||||
|  |  | ||||||
|  |   * bug #285 changed response header from 200 to 401 when empty token received | ||||||
|  |   * bug #286 adds documentation and links to spec for not including error messages when no token is supplied | ||||||
|  |   * bug #280 ensures PHP warnings do not get thrown as a result of an invalid argument to $jwt->decode() | ||||||
|  |   * bug #279 predis wrong number of arguments | ||||||
|  |   * bug #277 Securing JS WebApp client secret w/ password grant type | ||||||
|  |  | ||||||
|  | * 1.1 (2013-12-17) | ||||||
|  |  | ||||||
|  |   PR: https://github.com/bshaffer/oauth2-server-php/pull/276 | ||||||
|  |  | ||||||
|  |   * bug #278 adds refresh token configuration to Server class | ||||||
|  |   * bug #274 Supplying a null client_id and client_secret grants API access | ||||||
|  |   * bug #244 [MongoStorage] More detailed implementation info | ||||||
|  |   * bug #268 Implement jti for JWT Bearer tokens to prevent replay attacks. | ||||||
|  |   * bug #266 Removing unused argument to getAccessTokenData | ||||||
|  |   * bug #247 Make Bearer token type consistent | ||||||
|  |   * bug #253 Fixing CryptoToken refresh token lifetime | ||||||
|  |   * bug #246 refactors public key logic to be more intuitive | ||||||
|  |   * bug #245 adds support for JSON crypto tokens | ||||||
|  |   * bug #230 Remove unused columns in oauth_clients | ||||||
|  |   * bug #215 makes Redis Scope Storage obey the same paradigm as PDO | ||||||
|  |   * bug #228 removes scope group | ||||||
|  |   * bug #227 squelches open basedir restriction error | ||||||
|  |   * bug #223 Updated docblocks for RefreshTokenInterface.php | ||||||
|  |   * bug #224 Adds protected properties | ||||||
|  |   * bug #217 Implement ScopeInterface for PDO, Redis | ||||||
|  |  | ||||||
|  | * 1.0 (2013-08-12) | ||||||
|  |  | ||||||
|  |   * bug #203 Add redirect\_status_code config param for AuthorizeController | ||||||
|  |   * bug #205 ensures unnecessary ? is not set when  ** bug | ||||||
|  |   * bug #204 Fixed call to LogicException | ||||||
|  |   * bug #202 Add explode to checkRestrictedGrant in PDO Storage | ||||||
|  |   * bug #197 adds support for 'false' default scope  ** bug | ||||||
|  |   * bug #192 reference errors and adds tests | ||||||
|  |   * bug #194 makes some appropriate properties  ** bug | ||||||
|  |   * bug #191 passes config to HttpBasic | ||||||
|  |   * bug #190 validates client credentials before  ** bug | ||||||
|  |   * bug #171 Fix wrong redirect following authorization step | ||||||
|  |   * bug #187 client_id is now passed to getDefaultScope(). | ||||||
|  |   * bug #176 Require refresh_token in getRefreshToken response | ||||||
|  |   * bug #174 make user\_id not required for refresh_token grant | ||||||
|  |   * bug #173 Duplication in JwtBearer Grant | ||||||
|  |   * bug #168 user\_id not required for authorization_code grant | ||||||
|  |   * bug #133 hardens default security for user object | ||||||
|  |   * bug #163 allows redirect\_uri on authorization_code to be NULL in docs example | ||||||
|  |   * bug #162 adds getToken on ResourceController for convenience | ||||||
|  |   * bug #161 fixes fatal error | ||||||
|  |   * bug #163 Invalid redirect_uri handling | ||||||
|  |   * bug #156 user\_id in OAuth2\_Storage_AuthorizationCodeInterface::getAuthorizationCode() response | ||||||
|  |   * bug #157 Fix for extending access and refresh tokens | ||||||
|  |   * bug #154 ResponseInterface: getParameter method is used in the library but not defined in the interface | ||||||
|  |   * bug #148 Add more detail to examples in Readme.md | ||||||
							
								
								
									
										21
									
								
								library/oauth2/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								library/oauth2/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License | ||||||
|  |  | ||||||
|  | Copyright (c) 2014 Brent Shaffer | ||||||
|  |  | ||||||
|  | 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 the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  | THE SOFTWARE. | ||||||
							
								
								
									
										8
									
								
								library/oauth2/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								library/oauth2/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | oauth2-server-php | ||||||
|  | ================= | ||||||
|  |  | ||||||
|  | [](https://travis-ci.org/bshaffer/oauth2-server-php) | ||||||
|  |  | ||||||
|  | [](https://packagist.org/packages/bshaffer/oauth2-server-php) | ||||||
|  |  | ||||||
|  | View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/) | ||||||
							
								
								
									
										25
									
								
								library/oauth2/phpunit.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								library/oauth2/phpunit.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  |  | ||||||
|  | <phpunit backupGlobals="false" | ||||||
|  |          backupStaticAttributes="false" | ||||||
|  |          colors="true" | ||||||
|  |          convertErrorsToExceptions="true" | ||||||
|  |          convertNoticesToExceptions="true" | ||||||
|  |          convertWarningsToExceptions="true" | ||||||
|  |          processIsolation="false" | ||||||
|  |          stopOnFailure="false" | ||||||
|  |          syntaxCheck="false" | ||||||
|  |          bootstrap="test/bootstrap.php" | ||||||
|  | > | ||||||
|  |   <testsuites> | ||||||
|  |     <testsuite name="Oauth2 Test Suite"> | ||||||
|  |       <directory>./test/OAuth2/</directory> | ||||||
|  |     </testsuite> | ||||||
|  |   </testsuites> | ||||||
|  |  | ||||||
|  |   <filter> | ||||||
|  |     <whitelist> | ||||||
|  |       <directory suffix=".php">./src/OAuth2/</directory> | ||||||
|  |     </whitelist> | ||||||
|  |   </filter> | ||||||
|  | </phpunit> | ||||||
							
								
								
									
										48
									
								
								library/oauth2/src/OAuth2/Autoloader.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								library/oauth2/src/OAuth2/Autoloader.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Autoloads OAuth2 classes | ||||||
|  |  * | ||||||
|  |  * @author    Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  * @license   MIT License | ||||||
|  |  */ | ||||||
|  | class Autoloader | ||||||
|  | { | ||||||
|  |     private $dir; | ||||||
|  |  | ||||||
|  |     public function __construct($dir = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($dir)) { | ||||||
|  |             $dir = dirname(__FILE__).'/..'; | ||||||
|  |         } | ||||||
|  |         $this->dir = $dir; | ||||||
|  |     } | ||||||
|  |     /** | ||||||
|  |      * Registers OAuth2\Autoloader as an SPL autoloader. | ||||||
|  |      */ | ||||||
|  |     public static function register($dir = null) | ||||||
|  |     { | ||||||
|  |         ini_set('unserialize_callback_func', 'spl_autoload_call'); | ||||||
|  |         spl_autoload_register(array(new self($dir), 'autoload')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handles autoloading of classes. | ||||||
|  |      * | ||||||
|  |      * @param string $class A class name. | ||||||
|  |      * | ||||||
|  |      * @return boolean Returns true if the class has been loaded | ||||||
|  |      */ | ||||||
|  |     public function autoload($class) | ||||||
|  |     { | ||||||
|  |         if (0 !== strpos($class, 'OAuth2')) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) { | ||||||
|  |             require $file; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ClientAssertionType; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Interface for all OAuth2 Client Assertion Types | ||||||
|  |  */ | ||||||
|  | interface ClientAssertionTypeInterface | ||||||
|  | { | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response); | ||||||
|  |     public function getClientId(); | ||||||
|  | } | ||||||
							
								
								
									
										123
									
								
								library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ClientAssertionType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\ClientCredentialsInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Validate a client via Http Basic authentication | ||||||
|  |  * | ||||||
|  |  * @author    Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class HttpBasic implements ClientAssertionTypeInterface | ||||||
|  | { | ||||||
|  |     private $clientData; | ||||||
|  |  | ||||||
|  |     protected $storage; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information | ||||||
|  |      * @param array                                     $config        OPTIONAL Configuration options for the server | ||||||
|  |      *                                                                 <code> | ||||||
|  |      *                                                                 $config = array( | ||||||
|  |      *                                                                 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header | ||||||
|  |      *                                                                 'allow_public_clients'  => true              // if true, "public clients" (clients without a secret) may be authenticated | ||||||
|  |      *                                                                 ); | ||||||
|  |      *                                                                 </code> | ||||||
|  |      */ | ||||||
|  |     public function __construct(ClientCredentialsInterface $storage, array $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->storage = $storage; | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'allow_credentials_in_request_body' => true, | ||||||
|  |             'allow_public_clients' => true, | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$clientData = $this->getClientCredentials($request, $response)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($clientData['client_id'])) { | ||||||
|  |             throw new \LogicException('the clientData array must have "client_id" set'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') { | ||||||
|  |             if (!$this->config['allow_public_clients']) { | ||||||
|  |                 $response->setError(400, 'invalid_client', 'client credentials are required'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!$this->storage->isPublicClient($clientData['client_id'])) { | ||||||
|  |                 $response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) { | ||||||
|  |             $response->setError(400, 'invalid_client', 'The client credentials are invalid'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->clientData = $clientData; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return $this->clientData['client_id']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Internal function used to get the client credentials from HTTP basic | ||||||
|  |      * auth or POST data. | ||||||
|  |      * | ||||||
|  |      * According to the spec (draft 20), the client_id can be provided in | ||||||
|  |      * the Basic Authorization header (recommended) or via GET/POST. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * A list containing the client identifier and password, for example | ||||||
|  |      * @code | ||||||
|  |      * return array( | ||||||
|  |      *     "client_id"     => CLIENT_ID,        // REQUIRED the client id | ||||||
|  |      *     "client_secret" => CLIENT_SECRET,    // OPTIONAL the client secret (may be omitted for public clients) | ||||||
|  |      * ); | ||||||
|  |      * @endcode | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_2 | ||||||
|  |      */ | ||||||
|  |     public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { | ||||||
|  |             return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($this->config['allow_credentials_in_request_body']) { | ||||||
|  |             // Using POST for HttpBasic authorization is not recommended, but is supported by specification | ||||||
|  |             if (!is_null($request->request('client_id'))) { | ||||||
|  |                 /** | ||||||
|  |                  * client_secret can be null if the client's password is an empty string | ||||||
|  |                  * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 | ||||||
|  |                  */ | ||||||
|  |  | ||||||
|  |                 return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($response) { | ||||||
|  |             $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : ''; | ||||||
|  |             $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers'.$message); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										388
									
								
								library/oauth2/src/OAuth2/Controller/AuthorizeController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								library/oauth2/src/OAuth2/Controller/AuthorizeController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,388 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\ClientInterface; | ||||||
|  | use OAuth2\ScopeInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  | use OAuth2\Scope; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see OAuth2\Controller\AuthorizeControllerInterface | ||||||
|  |  */ | ||||||
|  | class AuthorizeController implements AuthorizeControllerInterface | ||||||
|  | { | ||||||
|  |     private $scope; | ||||||
|  |     private $state; | ||||||
|  |     private $client_id; | ||||||
|  |     private $redirect_uri; | ||||||
|  |     private $response_type; | ||||||
|  |  | ||||||
|  |     protected $clientStorage; | ||||||
|  |     protected $responseTypes; | ||||||
|  |     protected $config; | ||||||
|  |     protected $scopeUtil; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information | ||||||
|  |      * @param array                          $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects.  Valid array | ||||||
|  |      *                                                      keys are "code" and "token" | ||||||
|  |      * @param array                          $config        OPTIONAL Configuration options for the server | ||||||
|  |      *                                                      <code> | ||||||
|  |      *                                                      $config = array( | ||||||
|  |      *                                                      'allow_implicit' => false,            // if the controller should allow the "implicit" grant type | ||||||
|  |      *                                                      'enforce_state'  => true              // if the controller should require the "state" parameter | ||||||
|  |      *                                                      'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter | ||||||
|  |      *                                                      'redirect_status_code' => 302,        // HTTP status code to use for redirect responses | ||||||
|  |      *                                                      ); | ||||||
|  |      *                                                      </code> | ||||||
|  |      * @param OAuth2\ScopeInterface          $scopeUtil     OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope | ||||||
|  |      */ | ||||||
|  |     public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->clientStorage = $clientStorage; | ||||||
|  |         $this->responseTypes = $responseTypes; | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'allow_implicit' => false, | ||||||
|  |             'enforce_state'  => true, | ||||||
|  |             'require_exact_redirect_uri' => true, | ||||||
|  |             'redirect_status_code' => 302, | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         if (is_null($scopeUtil)) { | ||||||
|  |             $scopeUtil = new Scope(); | ||||||
|  |         } | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) | ||||||
|  |     { | ||||||
|  |         if (!is_bool($is_authorized)) { | ||||||
|  |             throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean.  This method must know if the user has granted access to the client.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // We repeat this, because we need to re-validate. The request could be POSTed | ||||||
|  |         // by a 3rd-party (because we are not internally enforcing NONCEs, etc) | ||||||
|  |         if (!$this->validateAuthorizeRequest($request, $response)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // If no redirect_uri is passed in the request, use client's registered one | ||||||
|  |         if (empty($this->redirect_uri)) { | ||||||
|  |             $clientData              = $this->clientStorage->getClientDetails($this->client_id); | ||||||
|  |             $registered_redirect_uri = $clientData['redirect_uri']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the user declined access to the client's application | ||||||
|  |         if ($is_authorized === false) { | ||||||
|  |             $redirect_uri = $this->redirect_uri ?: $registered_redirect_uri; | ||||||
|  |             $this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // build the parameters to set in the redirect URI | ||||||
|  |         if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id); | ||||||
|  |  | ||||||
|  |         list($redirect_uri, $uri_params) = $authResult; | ||||||
|  |  | ||||||
|  |         if (empty($redirect_uri) && !empty($registered_redirect_uri)) { | ||||||
|  |             $redirect_uri = $registered_redirect_uri; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $uri = $this->buildUri($redirect_uri, $uri_params); | ||||||
|  |  | ||||||
|  |         // return redirect response | ||||||
|  |         $response->setRedirect($this->config['redirect_status_code'], $uri); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $error = 'access_denied'; | ||||||
|  |         $error_message = 'The user denied access to your application'; | ||||||
|  |         $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * We have made this protected so this class can be extended to add/modify | ||||||
|  |      * these parameters | ||||||
|  |      */ | ||||||
|  |     protected function buildAuthorizeParameters($request, $response, $user_id) | ||||||
|  |     { | ||||||
|  |         // @TODO: we should be explicit with this in the future | ||||||
|  |         $params = array( | ||||||
|  |             'scope'         => $this->scope, | ||||||
|  |             'state'         => $this->state, | ||||||
|  |             'client_id'     => $this->client_id, | ||||||
|  |             'redirect_uri'  => $this->redirect_uri, | ||||||
|  |             'response_type' => $this->response_type, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return $params; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI) | ||||||
|  |         if (!$client_id = $request->query('client_id', $request->request('client_id'))) { | ||||||
|  |             // We don't have a good URI to use | ||||||
|  |             $response->setError(400, 'invalid_client', "No client id supplied"); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Get client details | ||||||
|  |         if (!$clientData = $this->clientStorage->getClientDetails($client_id)) { | ||||||
|  |             $response->setError(400, 'invalid_client', 'The client id supplied is invalid'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : ''; | ||||||
|  |  | ||||||
|  |         // Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI. | ||||||
|  |         // @see http://tools.ietf.org/html/rfc6749#section-3.1.2 | ||||||
|  |         // @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1 | ||||||
|  |         // @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1 | ||||||
|  |         if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) { | ||||||
|  |             // validate there is no fragment supplied | ||||||
|  |             $parts = parse_url($supplied_redirect_uri); | ||||||
|  |             if (isset($parts['fragment']) && $parts['fragment']) { | ||||||
|  |                 $response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // validate against the registered redirect uri(s) if available | ||||||
|  |             if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) { | ||||||
|  |                 $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             $redirect_uri = $supplied_redirect_uri; | ||||||
|  |         } else { | ||||||
|  |             // use the registered redirect_uri if none has been supplied, if possible | ||||||
|  |             if (!$registered_redirect_uri) { | ||||||
|  |                 $response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (count(explode(' ', $registered_redirect_uri)) > 1) { | ||||||
|  |                 $response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             $redirect_uri = $registered_redirect_uri; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Select the redirect URI | ||||||
|  |         $response_type = $request->query('response_type', $request->request('response_type')); | ||||||
|  |  | ||||||
|  |         // for multiple-valued response types - make them alphabetical | ||||||
|  |         if (false !== strpos($response_type, ' ')) { | ||||||
|  |             $types = explode(' ', $response_type); | ||||||
|  |             sort($types); | ||||||
|  |             $response_type = ltrim(implode(' ', $types)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $state = $request->query('state', $request->request('state')); | ||||||
|  |  | ||||||
|  |         // type and client_id are required | ||||||
|  |         if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) { | ||||||
|  |             $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { | ||||||
|  |             if (!isset($this->responseTypes['code'])) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) { | ||||||
|  |                 $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied'); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (!$this->config['allow_implicit']) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // validate requested scope if it exists | ||||||
|  |         $requestedScope = $this->scopeUtil->getScopeFromRequest($request); | ||||||
|  |  | ||||||
|  |         if ($requestedScope) { | ||||||
|  |             // restrict scope by client specific scope if applicable, | ||||||
|  |             // otherwise verify the scope exists | ||||||
|  |             $clientScope = $this->clientStorage->getClientScope($client_id); | ||||||
|  |             if ((empty($clientScope) && !$this->scopeUtil->scopeExists($requestedScope)) | ||||||
|  |                 || (!empty($clientScope) && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // use a globally-defined default scope | ||||||
|  |             $defaultScope = $this->scopeUtil->getDefaultScope($client_id); | ||||||
|  |  | ||||||
|  |             if (false === $defaultScope) { | ||||||
|  |                 $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $requestedScope = $defaultScope; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Validate state parameter exists (if configured to enforce this) | ||||||
|  |         if ($this->config['enforce_state'] && !$state) { | ||||||
|  |             $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // save the input data and return true | ||||||
|  |         $this->scope         = $requestedScope; | ||||||
|  |         $this->state         = $state; | ||||||
|  |         $this->client_id     = $client_id; | ||||||
|  |         // Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3) | ||||||
|  |         $this->redirect_uri  = $supplied_redirect_uri; | ||||||
|  |         $this->response_type = $response_type; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build the absolute URI based on supplied URI and parameters. | ||||||
|  |      * | ||||||
|  |      * @param $uri    An absolute URI. | ||||||
|  |      * @param $params Parameters to be append as GET. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An absolute URI with supplied parameters. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     private function buildUri($uri, $params) | ||||||
|  |     { | ||||||
|  |         $parse_url = parse_url($uri); | ||||||
|  |  | ||||||
|  |         // Add our params to the parsed uri | ||||||
|  |         foreach ($params as $k => $v) { | ||||||
|  |             if (isset($parse_url[$k])) { | ||||||
|  |                 $parse_url[$k] .= "&" . http_build_query($v, '', '&'); | ||||||
|  |             } else { | ||||||
|  |                 $parse_url[$k] = http_build_query($v, '', '&'); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Put humpty dumpty back together | ||||||
|  |         return | ||||||
|  |             ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "") | ||||||
|  |             . ((isset($parse_url["user"])) ? $parse_url["user"] | ||||||
|  |             . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "") | ||||||
|  |             . ((isset($parse_url["host"])) ? $parse_url["host"] : "") | ||||||
|  |             . ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "") | ||||||
|  |             . ((isset($parse_url["path"])) ? $parse_url["path"] : "") | ||||||
|  |             . ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "") | ||||||
|  |             . ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "") | ||||||
|  |         ; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getValidResponseTypes() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             self::RESPONSE_TYPE_ACCESS_TOKEN, | ||||||
|  |             self::RESPONSE_TYPE_AUTHORIZATION_CODE, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Internal method for validating redirect URI supplied | ||||||
|  |      * | ||||||
|  |      * @param string $inputUri            The submitted URI to be validated | ||||||
|  |      * @param string $registeredUriString The allowed URI(s) to validate against.  Can be a space-delimited string of URIs to | ||||||
|  |      *                                    allow for multiple URIs | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-3.1.2 | ||||||
|  |      */ | ||||||
|  |     protected function validateRedirectUri($inputUri, $registeredUriString) | ||||||
|  |     { | ||||||
|  |         if (!$inputUri || !$registeredUriString) { | ||||||
|  |             return false; // if either one is missing, assume INVALID | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $registered_uris = explode(' ', $registeredUriString); | ||||||
|  |         foreach ($registered_uris as $registered_uri) { | ||||||
|  |             if ($this->config['require_exact_redirect_uri']) { | ||||||
|  |                 // the input uri is validated against the registered uri using exact match | ||||||
|  |                 if (strcmp($inputUri, $registered_uri) === 0) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 $registered_uri_length = strlen($registered_uri); | ||||||
|  |                 if ($registered_uri_length === 0) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // the input uri is validated against the registered uri using case-insensitive match of the initial string | ||||||
|  |                 // i.e. additional query parameters may be applied | ||||||
|  |                 if (strcasecmp(substr($inputUri, 0, $registered_uri_length), $registered_uri) === 0) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Convenience methods to access the parameters derived from the validated request | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         return $this->scope; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getState() | ||||||
|  |     { | ||||||
|  |         return $this->state; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return $this->client_id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getRedirectUri() | ||||||
|  |     { | ||||||
|  |         return $this->redirect_uri; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResponseType() | ||||||
|  |     { | ||||||
|  |         return $this->response_type; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,43 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  *  This controller is called when a user should be authorized | ||||||
|  |  *  by an authorization server.  As OAuth2 does not handle | ||||||
|  |  *  authorization directly, this controller ensures the request is valid, but | ||||||
|  |  *  requires the application to determine the value of $is_authorized | ||||||
|  |  * | ||||||
|  |  *  ex: | ||||||
|  |  *  > $user_id = $this->somehowDetermineUserId(); | ||||||
|  |  *  > $is_authorized = $this->somehowDetermineUserAuthorization(); | ||||||
|  |  *  > $response = new OAuth2\Response(); | ||||||
|  |  *  > $authorizeController->handleAuthorizeRequest( | ||||||
|  |  *  >     OAuth2\Request::createFromGlobals(), | ||||||
|  |  *  >     $response, | ||||||
|  |  *  >     $is_authorized, | ||||||
|  |  *  >     $user_id); | ||||||
|  |  *  > $response->send(); | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | interface AuthorizeControllerInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * List of possible authentication response types. | ||||||
|  |      * The "authorization_code" mechanism exclusively supports 'code' | ||||||
|  |      * and the "implicit" mechanism exclusively supports 'token'. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.1 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.2.1 | ||||||
|  |      */ | ||||||
|  |     const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code'; | ||||||
|  |     const RESPONSE_TYPE_ACCESS_TOKEN = 'token'; | ||||||
|  |  | ||||||
|  |     public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null); | ||||||
|  |  | ||||||
|  |     public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response); | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								library/oauth2/src/OAuth2/Controller/ResourceController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								library/oauth2/src/OAuth2/Controller/ResourceController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\TokenType\TokenTypeInterface; | ||||||
|  | use OAuth2\Storage\AccessTokenInterface; | ||||||
|  | use OAuth2\ScopeInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  | use OAuth2\Scope; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see OAuth2\Controller\ResourceControllerInterface | ||||||
|  |  */ | ||||||
|  | class ResourceController implements ResourceControllerInterface | ||||||
|  | { | ||||||
|  |     private $token; | ||||||
|  |  | ||||||
|  |     protected $tokenType; | ||||||
|  |     protected $tokenStorage; | ||||||
|  |     protected $config; | ||||||
|  |     protected $scopeUtil; | ||||||
|  |  | ||||||
|  |     public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->tokenType = $tokenType; | ||||||
|  |         $this->tokenStorage = $tokenStorage; | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'www_realm' => 'Service', | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         if (is_null($scopeUtil)) { | ||||||
|  |             $scopeUtil = new Scope(); | ||||||
|  |         } | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null) | ||||||
|  |     { | ||||||
|  |         $token = $this->getAccessTokenData($request, $response); | ||||||
|  |  | ||||||
|  |         // Check if we have token data | ||||||
|  |         if (is_null($token)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Check scope, if provided | ||||||
|  |          * If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403 | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6750#section-3.1 | ||||||
|  |          */ | ||||||
|  |         if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) { | ||||||
|  |             $response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token'); | ||||||
|  |             $response->addHttpHeaders(array( | ||||||
|  |                 'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"', | ||||||
|  |                     $this->tokenType->getTokenType(), | ||||||
|  |                     $this->config['www_realm'], | ||||||
|  |                     $scope, | ||||||
|  |                     $response->getParameter('error'), | ||||||
|  |                     $response->getParameter('error_description') | ||||||
|  |                 ) | ||||||
|  |             )); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // allow retrieval of the token | ||||||
|  |         $this->token = $token; | ||||||
|  |  | ||||||
|  |         return (bool) $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAccessTokenData(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         // Get the token parameter | ||||||
|  |         if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) { | ||||||
|  |             // Get the stored token data (from the implementing subclass) | ||||||
|  |             // Check we have a well formed token | ||||||
|  |             // Check token expiration (expires is a mandatory paramter) | ||||||
|  |             if (!$token = $this->tokenStorage->getAccessToken($token_param)) { | ||||||
|  |                 $response->setError(401, 'invalid_token', 'The access token provided is invalid'); | ||||||
|  |             } elseif (!isset($token["expires"]) || !isset($token["client_id"])) { | ||||||
|  |                 $response->setError(401, 'malformed_token', 'Malformed token (missing "expires")'); | ||||||
|  |             } elseif (time() > $token["expires"]) { | ||||||
|  |                 $response->setError(401, 'expired_token', 'The access token provided has expired'); | ||||||
|  |             } else { | ||||||
|  |                 return $token; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']); | ||||||
|  |  | ||||||
|  |         if ($error = $response->getParameter('error')) { | ||||||
|  |             $authHeader = sprintf('%s, error="%s"', $authHeader, $error); | ||||||
|  |             if ($error_description = $response->getParameter('error_description')) { | ||||||
|  |                 $authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $response->addHttpHeaders(array('WWW-Authenticate' => $authHeader)); | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // convenience method to allow retrieval of the token | ||||||
|  |     public function getToken() | ||||||
|  |     { | ||||||
|  |         return $this->token; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  *  This controller is called when a "resource" is requested. | ||||||
|  |  *  call verifyResourceRequest in order to determine if the request | ||||||
|  |  *  contains a valid token. | ||||||
|  |  * | ||||||
|  |  *  ex: | ||||||
|  |  *  > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) { | ||||||
|  |  *  >     $response->send(); // authorization failed | ||||||
|  |  *  >     die(); | ||||||
|  |  *  > } | ||||||
|  |  *  > return json_encode($resource); // valid token!  Send the stuff! | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | interface ResourceControllerInterface | ||||||
|  | { | ||||||
|  |     public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null); | ||||||
|  |  | ||||||
|  |     public function getAccessTokenData(RequestInterface $request, ResponseInterface $response); | ||||||
|  | } | ||||||
							
								
								
									
										278
									
								
								library/oauth2/src/OAuth2/Controller/TokenController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								library/oauth2/src/OAuth2/Controller/TokenController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; | ||||||
|  | use OAuth2\GrantType\GrantTypeInterface; | ||||||
|  | use OAuth2\ScopeInterface; | ||||||
|  | use OAuth2\Scope; | ||||||
|  | use OAuth2\Storage\ClientInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see OAuth2\Controller\TokenControllerInterface | ||||||
|  |  */ | ||||||
|  | class TokenController implements TokenControllerInterface | ||||||
|  | { | ||||||
|  |     protected $accessToken; | ||||||
|  |     protected $grantTypes; | ||||||
|  |     protected $clientAssertionType; | ||||||
|  |     protected $scopeUtil; | ||||||
|  |     protected $clientStorage; | ||||||
|  |  | ||||||
|  |     public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($clientAssertionType)) { | ||||||
|  |             foreach ($grantTypes as $grantType) { | ||||||
|  |                 if (!$grantType instanceof ClientAssertionTypeInterface) { | ||||||
|  |                     throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface'); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $this->clientAssertionType = $clientAssertionType; | ||||||
|  |         $this->accessToken = $accessToken; | ||||||
|  |         $this->clientStorage = $clientStorage; | ||||||
|  |         foreach ($grantTypes as $grantType) { | ||||||
|  |             $this->addGrantType($grantType); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_null($scopeUtil)) { | ||||||
|  |             $scopeUtil = new Scope(); | ||||||
|  |         } | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleTokenRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if ($token = $this->grantAccessToken($request, $response)) { | ||||||
|  |             // @see http://tools.ietf.org/html/rfc6749#section-5.1 | ||||||
|  |             // server MUST disable caching in headers when tokens are involved | ||||||
|  |             $response->setStatusCode(200); | ||||||
|  |             $response->addParameters($token); | ||||||
|  |             $response->addHttpHeaders(array( | ||||||
|  |                 'Cache-Control' => 'no-store', | ||||||
|  |                 'Pragma' => 'no-cache', | ||||||
|  |                 'Content-Type' => 'application/json' | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Grant or deny a requested access token. | ||||||
|  |      * This would be called from the "/token" endpoint as defined in the spec. | ||||||
|  |      * You can call your endpoint whatever you want. | ||||||
|  |      * | ||||||
|  |      * @param $request - RequestInterface | ||||||
|  |      * Request object to grant access token | ||||||
|  |      * | ||||||
|  |      * @throws InvalidArgumentException | ||||||
|  |      * @throws LogicException | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-10.6 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function grantAccessToken(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (strtolower($request->server('REQUEST_METHOD')) != 'post') { | ||||||
|  |             $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); | ||||||
|  |             $response->addHttpHeaders(array('Allow' => 'POST')); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Determine grant type from request | ||||||
|  |          * and validate the request for that grant type | ||||||
|  |          */ | ||||||
|  |         if (!$grantTypeIdentifier = $request->request('grant_type')) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($this->grantTypes[$grantTypeIdentifier])) { | ||||||
|  |             /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ | ||||||
|  |             $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $grantType = $this->grantTypes[$grantTypeIdentifier]; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Retrieve the client information from the request | ||||||
|  |          * ClientAssertionTypes allow for grant types which also assert the client data | ||||||
|  |          * in which case ClientAssertion is handled in the validateRequest method | ||||||
|  |          * | ||||||
|  |          * @see OAuth2\GrantType\JWTBearer | ||||||
|  |          * @see OAuth2\GrantType\ClientCredentials | ||||||
|  |          */ | ||||||
|  |         if (!$grantType instanceof ClientAssertionTypeInterface) { | ||||||
|  |             if (!$this->clientAssertionType->validateRequest($request, $response)) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |             $clientId = $this->clientAssertionType->getClientId(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Retrieve the grant type information from the request | ||||||
|  |          * The GrantTypeInterface object handles all validation | ||||||
|  |          * If the object is an instance of ClientAssertionTypeInterface, | ||||||
|  |          * That logic is handled here as well | ||||||
|  |          */ | ||||||
|  |         if (!$grantType->validateRequest($request, $response)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($grantType instanceof ClientAssertionTypeInterface) { | ||||||
|  |             $clientId = $grantType->getClientId(); | ||||||
|  |         } else { | ||||||
|  |             // validate the Client ID (if applicable) | ||||||
|  |             if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { | ||||||
|  |                 $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Validate the client can use the requested grant type | ||||||
|  |          */ | ||||||
|  |         if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) { | ||||||
|  |             $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Validate the scope of the token | ||||||
|  |          * | ||||||
|  |          * requestedScope - the scope specified in the token request | ||||||
|  |          * availableScope - the scope associated with the grant type | ||||||
|  |          *  ex: in the case of the "Authorization Code" grant type, | ||||||
|  |          *  the scope is specified in the authorize request | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6749#section-3.3 | ||||||
|  |          */ | ||||||
|  |  | ||||||
|  |         $requestedScope = $this->scopeUtil->getScopeFromRequest($request); | ||||||
|  |         $availableScope = $grantType->getScope(); | ||||||
|  |  | ||||||
|  |         if ($requestedScope) { | ||||||
|  |             // validate the requested scope | ||||||
|  |             if ($availableScope) { | ||||||
|  |                 if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) { | ||||||
|  |                     $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request'); | ||||||
|  |  | ||||||
|  |                     return null; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 // validate the client has access to this scope | ||||||
|  |                 if ($clientScope = $this->clientStorage->getClientScope($clientId)) { | ||||||
|  |                     if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) { | ||||||
|  |                         $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client'); | ||||||
|  |  | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                 } elseif (!$this->scopeUtil->scopeExists($requestedScope)) { | ||||||
|  |                     $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); | ||||||
|  |  | ||||||
|  |                     return null; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } elseif ($availableScope) { | ||||||
|  |             // use the scope associated with this grant type | ||||||
|  |             $requestedScope = $availableScope; | ||||||
|  |         } else { | ||||||
|  |             // use a globally-defined default scope | ||||||
|  |             $defaultScope = $this->scopeUtil->getDefaultScope($clientId); | ||||||
|  |  | ||||||
|  |             // "false" means default scopes are not allowed | ||||||
|  |             if (false === $defaultScope) { | ||||||
|  |                 $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter'); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $requestedScope = $defaultScope; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * addGrantType | ||||||
|  |      * | ||||||
|  |      * @param grantType - OAuth2\GrantTypeInterface | ||||||
|  |      * the grant type to add for the specified identifier | ||||||
|  |      * @param identifier - string | ||||||
|  |      * a string passed in as "grant_type" in the response that will call this grantType | ||||||
|  |      */ | ||||||
|  |     public function addGrantType(GrantTypeInterface $grantType, $identifier = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($identifier) || is_numeric($identifier)) { | ||||||
|  |             $identifier = $grantType->getQuerystringIdentifier(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->grantTypes[$identifier] = $grantType; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if ($this->revokeToken($request, $response)) { | ||||||
|  |             $response->setStatusCode(200); | ||||||
|  |             $response->addParameters(array('revoked' => true)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Revoke a refresh or access token. Returns true on success and when tokens are invalid | ||||||
|  |      * | ||||||
|  |      * Note: invalid tokens do not cause an error response since the client | ||||||
|  |      * cannot handle such an error in a reasonable way.  Moreover, the | ||||||
|  |      * purpose of the revocation request, invalidating the particular token, | ||||||
|  |      * is already achieved. | ||||||
|  |      * | ||||||
|  |      * @param RequestInterface $request | ||||||
|  |      * @param ResponseInterface $response | ||||||
|  |      * @return bool|null | ||||||
|  |      */ | ||||||
|  |     public function revokeToken(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (strtolower($request->server('REQUEST_METHOD')) != 'post') { | ||||||
|  |             $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2'); | ||||||
|  |             $response->addHttpHeaders(array('Allow' => 'POST')); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $token_type_hint = $request->request('token_type_hint'); | ||||||
|  |         if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\''); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $token = $request->request('token'); | ||||||
|  |         if ($token === null) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Missing token parameter to revoke'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // @todo remove this check for v2.0 | ||||||
|  |         if (!method_exists($this->accessToken, 'revokeToken')) { | ||||||
|  |             $class = get_class($this->accessToken); | ||||||
|  |             throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->accessToken->revokeToken($token, $token_type_hint); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  *  This controller is called when a token is being requested. | ||||||
|  |  *  it is called to handle all grant types the application supports. | ||||||
|  |  *  It also validates the client's credentials | ||||||
|  |  * | ||||||
|  |  *  ex: | ||||||
|  |  *  > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response()); | ||||||
|  |  *  > $response->send(); | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | interface TokenControllerInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * handleTokenRequest | ||||||
|  |      * | ||||||
|  |      * @param $request | ||||||
|  |      * OAuth2\RequestInterface - The current http request | ||||||
|  |      * @param $response | ||||||
|  |      * OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     public function handleTokenRequest(RequestInterface $request, ResponseInterface $response); | ||||||
|  |  | ||||||
|  |     public function grantAccessToken(RequestInterface $request, ResponseInterface $response); | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Encryption; | ||||||
|  |  | ||||||
|  | interface EncryptionInterface | ||||||
|  | { | ||||||
|  |     public function encode($payload, $key, $algorithm = null); | ||||||
|  |     public function decode($payload, $key, $algorithm = null); | ||||||
|  |     public function urlSafeB64Encode($data); | ||||||
|  |     public function urlSafeB64Decode($b64); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Encryption; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Bridge file to use the firebase/php-jwt package for JWT encoding and decoding. | ||||||
|  |  * @author Francis Chuang <francis.chuang@gmail.com> | ||||||
|  |  */ | ||||||
|  | class FirebaseJwt implements EncryptionInterface | ||||||
|  | { | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         if (!class_exists('\JWT')) { | ||||||
|  |             throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function encode($payload, $key, $alg = 'HS256', $keyId = null) | ||||||
|  |     { | ||||||
|  |         return \JWT::encode($payload, $key, $alg, $keyId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function decode($jwt, $key = null, $allowedAlgorithms = null) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |  | ||||||
|  |             //Maintain BC: Do not verify if no algorithms are passed in. | ||||||
|  |             if (!$allowedAlgorithms) { | ||||||
|  |                 $key = null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return (array)\JWT::decode($jwt, $key, $allowedAlgorithms); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function urlSafeB64Encode($data) | ||||||
|  |     { | ||||||
|  |         return \JWT::urlsafeB64Encode($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function urlSafeB64Decode($b64) | ||||||
|  |     { | ||||||
|  |         return \JWT::urlsafeB64Decode($b64); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										173
									
								
								library/oauth2/src/OAuth2/Encryption/Jwt.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								library/oauth2/src/OAuth2/Encryption/Jwt.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Encryption; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @link https://github.com/F21/jwt | ||||||
|  |  * @author F21 | ||||||
|  |  */ | ||||||
|  | class Jwt implements EncryptionInterface | ||||||
|  | { | ||||||
|  |     public function encode($payload, $key, $algo = 'HS256') | ||||||
|  |     { | ||||||
|  |         $header = $this->generateJwtHeader($payload, $algo); | ||||||
|  |  | ||||||
|  |         $segments = array( | ||||||
|  |             $this->urlSafeB64Encode(json_encode($header)), | ||||||
|  |             $this->urlSafeB64Encode(json_encode($payload)) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $signing_input = implode('.', $segments); | ||||||
|  |  | ||||||
|  |         $signature = $this->sign($signing_input, $key, $algo); | ||||||
|  |         $segments[] = $this->urlsafeB64Encode($signature); | ||||||
|  |  | ||||||
|  |         return implode('.', $segments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function decode($jwt, $key = null, $allowedAlgorithms = true) | ||||||
|  |     { | ||||||
|  |         if (!strpos($jwt, '.')) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $tks = explode('.', $jwt); | ||||||
|  |  | ||||||
|  |         if (count($tks) != 3) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         list($headb64, $payloadb64, $cryptob64) = $tks; | ||||||
|  |  | ||||||
|  |         if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $sig = $this->urlSafeB64Decode($cryptob64); | ||||||
|  |  | ||||||
|  |         if ((bool) $allowedAlgorithms) { | ||||||
|  |             if (!isset($header['alg'])) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // check if bool arg supplied here to maintain BC | ||||||
|  |             if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $payload; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function verifySignature($signature, $input, $key, $algo = 'HS256') | ||||||
|  |     { | ||||||
|  |         // use constants when possible, for HipHop support | ||||||
|  |         switch ($algo) { | ||||||
|  |             case'HS256': | ||||||
|  |             case'HS384': | ||||||
|  |             case'HS512': | ||||||
|  |                 return $this->hash_equals( | ||||||
|  |                     $this->sign($input, $key, $algo), | ||||||
|  |                     $signature | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |             case 'RS256': | ||||||
|  |                 return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256')  === 1; | ||||||
|  |  | ||||||
|  |             case 'RS384': | ||||||
|  |                 return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1; | ||||||
|  |  | ||||||
|  |             case 'RS512': | ||||||
|  |                 return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1; | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 throw new \InvalidArgumentException("Unsupported or invalid signing algorithm."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function sign($input, $key, $algo = 'HS256') | ||||||
|  |     { | ||||||
|  |         switch ($algo) { | ||||||
|  |             case 'HS256': | ||||||
|  |                 return hash_hmac('sha256', $input, $key, true); | ||||||
|  |  | ||||||
|  |             case 'HS384': | ||||||
|  |                 return hash_hmac('sha384', $input, $key, true); | ||||||
|  |  | ||||||
|  |             case 'HS512': | ||||||
|  |                 return hash_hmac('sha512', $input, $key, true); | ||||||
|  |  | ||||||
|  |             case 'RS256': | ||||||
|  |                 return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256'); | ||||||
|  |  | ||||||
|  |             case 'RS384': | ||||||
|  |                 return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384'); | ||||||
|  |  | ||||||
|  |             case 'RS512': | ||||||
|  |                 return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512'); | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 throw new \Exception("Unsupported or invalid signing algorithm."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function generateRSASignature($input, $key, $algo) | ||||||
|  |     { | ||||||
|  |         if (!openssl_sign($input, $signature, $key, $algo)) { | ||||||
|  |             throw new \Exception("Unable to sign data."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $signature; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function urlSafeB64Encode($data) | ||||||
|  |     { | ||||||
|  |         $b64 = base64_encode($data); | ||||||
|  |         $b64 = str_replace(array('+', '/', "\r", "\n", '='), | ||||||
|  |                 array('-', '_'), | ||||||
|  |                 $b64); | ||||||
|  |  | ||||||
|  |         return $b64; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function urlSafeB64Decode($b64) | ||||||
|  |     { | ||||||
|  |         $b64 = str_replace(array('-', '_'), | ||||||
|  |                 array('+', '/'), | ||||||
|  |                 $b64); | ||||||
|  |  | ||||||
|  |         return base64_decode($b64); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Override to create a custom header | ||||||
|  |      */ | ||||||
|  |     protected function generateJwtHeader($payload, $algorithm) | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             'typ' => 'JWT', | ||||||
|  |             'alg' => $algorithm, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function hash_equals($a, $b) | ||||||
|  |     { | ||||||
|  |         if (function_exists('hash_equals')) { | ||||||
|  |             return hash_equals($a, $b); | ||||||
|  |         } | ||||||
|  |         $diff = strlen($a) ^ strlen($b); | ||||||
|  |         for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) { | ||||||
|  |             $diff |= ord($a[$i]) ^ ord($b[$i]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $diff === 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\AuthorizationCodeInterface; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class AuthorizationCode implements GrantTypeInterface | ||||||
|  | { | ||||||
|  |     protected $storage; | ||||||
|  |     protected $authCode; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information | ||||||
|  |      */ | ||||||
|  |     public function __construct(AuthorizationCodeInterface $storage) | ||||||
|  |     { | ||||||
|  |         $this->storage = $storage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getQuerystringIdentifier() | ||||||
|  |     { | ||||||
|  |         return 'authorization_code'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$request->request('code')) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $code = $request->request('code'); | ||||||
|  |         if (!$authCode = $this->storage->getAuthorizationCode($code)) { | ||||||
|  |             $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request | ||||||
|  |          * @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3 | ||||||
|  |          */ | ||||||
|  |         if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) { | ||||||
|  |             if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) { | ||||||
|  |                 $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3"); | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($authCode['expires'])) { | ||||||
|  |             throw new \Exception('Storage must return authcode with a value for "expires"'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($authCode["expires"] < time()) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "The authorization code has expired"); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($authCode['code'])) { | ||||||
|  |             $authCode['code'] = $code; // used to expire the code after the access token is granted | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->authCode = $authCode; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return $this->authCode['client_id']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         return isset($this->authCode['scope']) ? $this->authCode['scope'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserId() | ||||||
|  |     { | ||||||
|  |         return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         $token = $accessToken->createAccessToken($client_id, $user_id, $scope); | ||||||
|  |         $this->storage->expireAuthorizationCode($this->authCode['code']); | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								library/oauth2/src/OAuth2/GrantType/ClientCredentials.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								library/oauth2/src/OAuth2/GrantType/ClientCredentials.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\ClientAssertionType\HttpBasic; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\Storage\ClientCredentialsInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  * | ||||||
|  |  * @see OAuth2\ClientAssertionType_HttpBasic | ||||||
|  |  */ | ||||||
|  | class ClientCredentials extends HttpBasic implements GrantTypeInterface | ||||||
|  | { | ||||||
|  |     private $clientData; | ||||||
|  |  | ||||||
|  |     public function __construct(ClientCredentialsInterface $storage, array $config = array()) | ||||||
|  |     { | ||||||
|  |         /** | ||||||
|  |          * The client credentials grant type MUST only be used by confidential clients | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6749#section-4.4 | ||||||
|  |          */ | ||||||
|  |         $config['allow_public_clients'] = false; | ||||||
|  |  | ||||||
|  |         parent::__construct($storage, $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getQuerystringIdentifier() | ||||||
|  |     { | ||||||
|  |         return 'client_credentials'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         $this->loadClientData(); | ||||||
|  |  | ||||||
|  |         return isset($this->clientData['scope']) ? $this->clientData['scope'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserId() | ||||||
|  |     { | ||||||
|  |         $this->loadClientData(); | ||||||
|  |  | ||||||
|  |         return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         /** | ||||||
|  |          * Client Credentials Grant does NOT include a refresh token | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6749#section-4.4.3 | ||||||
|  |          */ | ||||||
|  |         $includeRefreshToken = false; | ||||||
|  |  | ||||||
|  |         return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function loadClientData() | ||||||
|  |     { | ||||||
|  |         if (!$this->clientData) { | ||||||
|  |             $this->clientData = $this->storage->getClientDetails($this->getClientId()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Interface for all OAuth2 Grant Types | ||||||
|  |  */ | ||||||
|  | interface GrantTypeInterface | ||||||
|  | { | ||||||
|  |     public function getQuerystringIdentifier(); | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response); | ||||||
|  |     public function getClientId(); | ||||||
|  |     public function getUserId(); | ||||||
|  |     public function getScope(); | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope); | ||||||
|  | } | ||||||
							
								
								
									
										226
									
								
								library/oauth2/src/OAuth2/GrantType/JwtBearer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								library/oauth2/src/OAuth2/GrantType/JwtBearer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; | ||||||
|  | use OAuth2\Storage\JwtBearerInterface; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  | use OAuth2\Encryption\EncryptionInterface; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft. | ||||||
|  |  * | ||||||
|  |  * @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4 | ||||||
|  |  * | ||||||
|  |  * @author F21 | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface | ||||||
|  | { | ||||||
|  |     private $jwt; | ||||||
|  |  | ||||||
|  |     protected $storage; | ||||||
|  |     protected $audience; | ||||||
|  |     protected $jwtUtil; | ||||||
|  |     protected $allowedAlgorithms; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates an instance of the JWT bearer grant type. | ||||||
|  |      * | ||||||
|  |      * @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type. | ||||||
|  |      * @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint. | ||||||
|  |      * @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs. | ||||||
|  |      * @param array $config | ||||||
|  |      */ | ||||||
|  |     public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->storage = $storage; | ||||||
|  |         $this->audience = $audience; | ||||||
|  |  | ||||||
|  |         if (is_null($jwtUtil)) { | ||||||
|  |             $jwtUtil = new Jwt(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'allowed_algorithms' => array('RS256', 'RS384', 'RS512') | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         $this->jwtUtil = $jwtUtil; | ||||||
|  |  | ||||||
|  |         $this->allowedAlgorithms = $this->config['allowed_algorithms']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * The string identifier for grant_type. | ||||||
|  |      * | ||||||
|  |      * @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier() | ||||||
|  |      */ | ||||||
|  |     public function getQuerystringIdentifier() | ||||||
|  |     { | ||||||
|  |         return 'urn:ietf:params:oauth:grant-type:jwt-bearer'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Validates the data from the decoded JWT. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned. | ||||||
|  |      * | ||||||
|  |      * @see OAuth2\GrantType\GrantTypeInterface::getTokenData() | ||||||
|  |      */ | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$request->request("assertion")) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Store the undecoded JWT for later use | ||||||
|  |         $undecodedJWT = $request->request('assertion'); | ||||||
|  |  | ||||||
|  |         // Decode the JWT | ||||||
|  |         $jwt = $this->jwtUtil->decode($request->request('assertion'), null, false); | ||||||
|  |  | ||||||
|  |         if (!$jwt) { | ||||||
|  |             $response->setError(400, 'invalid_request', "JWT is malformed"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // ensure these properties contain a value | ||||||
|  |         // @todo: throw malformed error for missing properties | ||||||
|  |         $jwt = array_merge(array( | ||||||
|  |             'scope' => null, | ||||||
|  |             'iss' => null, | ||||||
|  |             'sub' => null, | ||||||
|  |             'aud' => null, | ||||||
|  |             'exp' => null, | ||||||
|  |             'nbf' => null, | ||||||
|  |             'iat' => null, | ||||||
|  |             'jti' => null, | ||||||
|  |             'typ' => null, | ||||||
|  |         ), $jwt); | ||||||
|  |  | ||||||
|  |         if (!isset($jwt['iss'])) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($jwt['sub'])) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Invalid subject (sub) provided"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($jwt['exp'])) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Expiration (exp) time must be present"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Check expiration | ||||||
|  |         if (ctype_digit($jwt['exp'])) { | ||||||
|  |             if ($jwt['exp'] <= time()) { | ||||||
|  |                 $response->setError(400, 'invalid_grant', "JWT has expired"); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Check the not before time | ||||||
|  |         if ($notBefore = $jwt['nbf']) { | ||||||
|  |             if (ctype_digit($notBefore)) { | ||||||
|  |                 if ($notBefore > time()) { | ||||||
|  |                     $response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time"); | ||||||
|  |  | ||||||
|  |                     return null; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 $response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp"); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Check the audience if required to match | ||||||
|  |         if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Invalid audience (aud)"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Check the jti (nonce) | ||||||
|  |         // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7 | ||||||
|  |         if (isset($jwt['jti'])) { | ||||||
|  |             $jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); | ||||||
|  |  | ||||||
|  |             //Reject if jti is used and jwt is still valid (exp parameter has not expired). | ||||||
|  |             if ($jti && $jti['expires'] > time()) { | ||||||
|  |                 $response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used"); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } else { | ||||||
|  |                 $this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Get the iss's public key | ||||||
|  |         // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1 | ||||||
|  |         if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Verify the JWT | ||||||
|  |         if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) { | ||||||
|  |             $response->setError(400, 'invalid_grant', "JWT failed signature verification"); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->jwt = $jwt; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return $this->jwt['iss']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserId() | ||||||
|  |     { | ||||||
|  |         return $this->jwt['sub']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates an access token that is NOT associated with a refresh token. | ||||||
|  |      * If a subject (sub) the name of the user/account we are accessing data on behalf of. | ||||||
|  |      * | ||||||
|  |      * @see OAuth2\GrantType\GrantTypeInterface::createAccessToken() | ||||||
|  |      */ | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         $includeRefreshToken = false; | ||||||
|  |  | ||||||
|  |         return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								library/oauth2/src/OAuth2/GrantType/RefreshToken.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								library/oauth2/src/OAuth2/GrantType/RefreshToken.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\RefreshTokenInterface; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class RefreshToken implements GrantTypeInterface | ||||||
|  | { | ||||||
|  |     private $refreshToken; | ||||||
|  |  | ||||||
|  |     protected $storage; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information | ||||||
|  |      * @param array                                $config  OPTIONAL Configuration options for the server | ||||||
|  |      *                                                      <code> | ||||||
|  |      *                                                      $config = array( | ||||||
|  |      *                                                      'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request | ||||||
|  |      *                                                      'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using | ||||||
|  |      *                                                      ); | ||||||
|  |      *                                                      </code> | ||||||
|  |      */ | ||||||
|  |     public function __construct(RefreshTokenInterface $storage, $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'always_issue_new_refresh_token' => false, | ||||||
|  |             'unset_refresh_token_after_use' => true | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         // to preserve B.C. with v1.6 | ||||||
|  |         // @see https://github.com/bshaffer/oauth2-server-php/pull/580 | ||||||
|  |         // @todo - remove in v2.0 | ||||||
|  |         if (isset($config['always_issue_new_refresh_token']) && !isset($config['unset_refresh_token_after_use'])) { | ||||||
|  |             $this->config['unset_refresh_token_after_use'] = $config['always_issue_new_refresh_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->storage = $storage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getQuerystringIdentifier() | ||||||
|  |     { | ||||||
|  |         return 'refresh_token'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$request->request("refresh_token")) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$refreshToken = $this->storage->getRefreshToken($request->request("refresh_token"))) { | ||||||
|  |             $response->setError(400, 'invalid_grant', 'Invalid refresh token'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) { | ||||||
|  |             $response->setError(400, 'invalid_grant', 'Refresh token has expired'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // store the refresh token locally so we can delete it when a new refresh token is generated | ||||||
|  |         $this->refreshToken = $refreshToken; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return $this->refreshToken['client_id']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserId() | ||||||
|  |     { | ||||||
|  |         return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         /* | ||||||
|  |          * It is optional to force a new refresh token when a refresh token is used. | ||||||
|  |          * However, if a new refresh token is issued, the old one MUST be expired | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6749#section-6 | ||||||
|  |          */ | ||||||
|  |         $issueNewRefreshToken = $this->config['always_issue_new_refresh_token']; | ||||||
|  |         $unsetRefreshToken = $this->config['unset_refresh_token_after_use']; | ||||||
|  |         $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken); | ||||||
|  |  | ||||||
|  |         if ($unsetRefreshToken) { | ||||||
|  |             $this->storage->unsetRefreshToken($this->refreshToken['refresh_token']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										83
									
								
								library/oauth2/src/OAuth2/GrantType/UserCredentials.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								library/oauth2/src/OAuth2/GrantType/UserCredentials.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\UserCredentialsInterface; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class UserCredentials implements GrantTypeInterface | ||||||
|  | { | ||||||
|  |     private $userInfo; | ||||||
|  |  | ||||||
|  |     protected $storage; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information | ||||||
|  |      */ | ||||||
|  |     public function __construct(UserCredentialsInterface $storage) | ||||||
|  |     { | ||||||
|  |         $this->storage = $storage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getQuerystringIdentifier() | ||||||
|  |     { | ||||||
|  |         return 'password'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$request->request("password") || !$request->request("username")) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) { | ||||||
|  |             $response->setError(401, 'invalid_grant', 'Invalid username and password combination'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $userInfo = $this->storage->getUserDetails($request->request("username")); | ||||||
|  |  | ||||||
|  |         if (empty($userInfo)) { | ||||||
|  |             $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($userInfo['user_id'])) { | ||||||
|  |             throw new \LogicException("you must set the user_id on the array returned by getUserDetails"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->userInfo = $userInfo; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientId() | ||||||
|  |     { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserId() | ||||||
|  |     { | ||||||
|  |         return $this->userInfo['user_id']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScope() | ||||||
|  |     { | ||||||
|  |         return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         return $accessToken->createAccessToken($client_id, $user_id, $scope); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Controller\AuthorizeController as BaseAuthorizeController; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see OAuth2\Controller\AuthorizeControllerInterface | ||||||
|  |  */ | ||||||
|  | class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface | ||||||
|  | { | ||||||
|  |     private $nonce; | ||||||
|  |  | ||||||
|  |     protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $prompt = $request->query('prompt', 'consent'); | ||||||
|  |         if ($prompt == 'none') { | ||||||
|  |             if (is_null($user_id)) { | ||||||
|  |                 $error = 'login_required'; | ||||||
|  |                 $error_message = 'The user must log in'; | ||||||
|  |             } else { | ||||||
|  |                 $error = 'interaction_required'; | ||||||
|  |                 $error_message = 'The user must grant access to your application'; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $error = 'consent_required'; | ||||||
|  |             $error_message = 'The user denied access to your application'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function buildAuthorizeParameters($request, $response, $user_id) | ||||||
|  |     { | ||||||
|  |         if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Generate an id token if needed. | ||||||
|  |         if ($this->needsIdToken($this->getScope()) && $this->getResponseType() == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { | ||||||
|  |             $params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->getClientId(), $user_id, $this->nonce); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // add the nonce to return with the redirect URI | ||||||
|  |         $params['nonce'] = $this->nonce; | ||||||
|  |  | ||||||
|  |         return $params; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!parent::validateAuthorizeRequest($request, $response)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $nonce = $request->query('nonce'); | ||||||
|  |  | ||||||
|  |         // Validate required nonce for "id_token" and "id_token token" | ||||||
|  |         if (!$nonce && in_array($this->getResponseType(), array(self::RESPONSE_TYPE_ID_TOKEN, self::RESPONSE_TYPE_ID_TOKEN_TOKEN))) { | ||||||
|  |             $response->setError(400, 'invalid_nonce', 'This application requires you specify a nonce parameter'); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->nonce = $nonce; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getValidResponseTypes() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             self::RESPONSE_TYPE_ACCESS_TOKEN, | ||||||
|  |             self::RESPONSE_TYPE_AUTHORIZATION_CODE, | ||||||
|  |             self::RESPONSE_TYPE_ID_TOKEN, | ||||||
|  |             self::RESPONSE_TYPE_ID_TOKEN_TOKEN, | ||||||
|  |             self::RESPONSE_TYPE_CODE_ID_TOKEN, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the current request needs to generate an id token. | ||||||
|  |      * | ||||||
|  |      * ID Tokens are a part of the OpenID Connect specification, so this | ||||||
|  |      * method checks whether OpenID Connect is enabled in the server settings | ||||||
|  |      * and whether the openid scope was requested. | ||||||
|  |      * | ||||||
|  |      * @param $request_scope | ||||||
|  |      *  A space-separated string of scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *   TRUE if an id token is needed, FALSE otherwise. | ||||||
|  |      */ | ||||||
|  |     public function needsIdToken($request_scope) | ||||||
|  |     { | ||||||
|  |         // see if the "openid" scope exists in the requested scope | ||||||
|  |         return $this->scopeUtil->checkScope('openid', $request_scope); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getNonce() | ||||||
|  |     { | ||||||
|  |         return $this->nonce; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | interface AuthorizeControllerInterface | ||||||
|  | { | ||||||
|  |     const RESPONSE_TYPE_ID_TOKEN = 'id_token'; | ||||||
|  |     const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token'; | ||||||
|  |     const RESPONSE_TYPE_CODE_ID_TOKEN  = 'code id_token'; | ||||||
|  | } | ||||||
| @@ -0,0 +1,58 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Scope; | ||||||
|  | use OAuth2\TokenType\TokenTypeInterface; | ||||||
|  | use OAuth2\Storage\AccessTokenInterface; | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  | use OAuth2\Controller\ResourceController; | ||||||
|  | use OAuth2\ScopeInterface; | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see OAuth2\Controller\UserInfoControllerInterface | ||||||
|  |  */ | ||||||
|  | class UserInfoController extends ResourceController implements UserInfoControllerInterface | ||||||
|  | { | ||||||
|  |     private $token; | ||||||
|  |  | ||||||
|  |     protected $tokenType; | ||||||
|  |     protected $tokenStorage; | ||||||
|  |     protected $userClaimsStorage; | ||||||
|  |     protected $config; | ||||||
|  |     protected $scopeUtil; | ||||||
|  |  | ||||||
|  |     public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->tokenType = $tokenType; | ||||||
|  |         $this->tokenStorage = $tokenStorage; | ||||||
|  |         $this->userClaimsStorage = $userClaimsStorage; | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'www_realm' => 'Service', | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         if (is_null($scopeUtil)) { | ||||||
|  |             $scopeUtil = new Scope(); | ||||||
|  |         } | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         if (!$this->verifyResourceRequest($request, $response, 'openid')) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $token = $this->getToken(); | ||||||
|  |         $claims = $this->userClaimsStorage->getUserClaims($token['user_id'], $token['scope']); | ||||||
|  |         // The sub Claim MUST always be returned in the UserInfo Response. | ||||||
|  |         // http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse | ||||||
|  |         $claims += array( | ||||||
|  |             'sub' => $token['user_id'], | ||||||
|  |         ); | ||||||
|  |         $response->addParameters($claims); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  *  This controller is called when the user claims for OpenID Connect's | ||||||
|  |  *  UserInfo endpoint should be returned. | ||||||
|  |  * | ||||||
|  |  *  ex: | ||||||
|  |  *  > $response = new OAuth2\Response(); | ||||||
|  |  *  > $userInfoController->handleUserInfoRequest( | ||||||
|  |  *  >     OAuth2\Request::createFromGlobals(), | ||||||
|  |  *  >     $response; | ||||||
|  |  *  > $response->send(); | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | interface UserInfoControllerInterface | ||||||
|  | { | ||||||
|  |     public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response); | ||||||
|  | } | ||||||
| @@ -0,0 +1,33 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode; | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class AuthorizationCode extends BaseAuthorizationCode | ||||||
|  | { | ||||||
|  |     public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) | ||||||
|  |     { | ||||||
|  |         $includeRefreshToken = true; | ||||||
|  |         if (isset($this->authCode['id_token'])) { | ||||||
|  |             // OpenID Connect requests include the refresh token only if the | ||||||
|  |             // offline_access scope has been requested and granted. | ||||||
|  |             $scopes = explode(' ', trim($scope)); | ||||||
|  |             $includeRefreshToken = in_array('offline_access', $scopes); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); | ||||||
|  |         if (isset($this->authCode['id_token'])) { | ||||||
|  |             $token['id_token'] = $this->authCode['id_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->storage->expireAuthorizationCode($this->authCode['code']); | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,60 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) | ||||||
|  |     { | ||||||
|  |         parent::__construct($storage, $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null) | ||||||
|  |     { | ||||||
|  |         // build the URL to redirect to | ||||||
|  |         $result = array('query' => array()); | ||||||
|  |  | ||||||
|  |         $params += array('scope' => null, 'state' => null, 'id_token' => null); | ||||||
|  |  | ||||||
|  |         $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']); | ||||||
|  |  | ||||||
|  |         if (isset($params['state'])) { | ||||||
|  |             $result['query']['state'] = $params['state']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array($params['redirect_uri'], $result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of the authorization code. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier related to the authorization code | ||||||
|  |      * @param $user_id | ||||||
|  |      * User ID associated with the authorization code | ||||||
|  |      * @param $redirect_uri | ||||||
|  |      * An absolute URI to which the authorization server will redirect the | ||||||
|  |      * user-agent to when the end-user authorization step is completed. | ||||||
|  |      * @param $scope | ||||||
|  |      * (optional) Scopes to be stored in space-separated string. | ||||||
|  |      * @param $id_token | ||||||
|  |      * (optional) The OpenID Connect id_token. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         $code = $this->generateAuthorizationCode(); | ||||||
|  |         $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token); | ||||||
|  |  | ||||||
|  |         return $code; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of the authorization code. | ||||||
|  |      * | ||||||
|  |      * @param $client_id                Client identifier related to the authorization code | ||||||
|  |      * @param $user_id                  User ID associated with the authorization code | ||||||
|  |      * @param $redirect_uri             An absolute URI to which the authorization server will redirect the | ||||||
|  |      *                                  user-agent to when the end-user authorization step is completed. | ||||||
|  |      * @param $scope        OPTIONAL    Scopes to be stored in space-separated string. | ||||||
|  |      * @param $id_token     OPTIONAL    The OpenID Connect id_token. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null); | ||||||
|  | } | ||||||
| @@ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | class CodeIdToken implements CodeIdTokenInterface | ||||||
|  | { | ||||||
|  |     protected $authCode; | ||||||
|  |     protected $idToken; | ||||||
|  |  | ||||||
|  |     public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken) | ||||||
|  |     { | ||||||
|  |         $this->authCode = $authCode; | ||||||
|  |         $this->idToken = $idToken; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $result = $this->authCode->getAuthorizeResponse($params, $user_id); | ||||||
|  |         $resultIdToken = $this->idToken->getAuthorizeResponse($params, $user_id); | ||||||
|  |         $result[1]['query']['id_token'] = $resultIdToken[1]['fragment']['id_token']; | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\ResponseTypeInterface; | ||||||
|  |  | ||||||
|  | interface CodeIdTokenInterface extends ResponseTypeInterface | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										124
									
								
								library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Encryption\EncryptionInterface; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  | use OAuth2\Storage\PublicKeyInterface; | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  |  | ||||||
|  | class IdToken implements IdTokenInterface | ||||||
|  | { | ||||||
|  |     protected $userClaimsStorage; | ||||||
|  |     protected $publicKeyStorage; | ||||||
|  |     protected $config; | ||||||
|  |     protected $encryptionUtil; | ||||||
|  |  | ||||||
|  |     public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->userClaimsStorage = $userClaimsStorage; | ||||||
|  |         $this->publicKeyStorage = $publicKeyStorage; | ||||||
|  |         if (is_null($encryptionUtil)) { | ||||||
|  |             $encryptionUtil = new Jwt(); | ||||||
|  |         } | ||||||
|  |         $this->encryptionUtil = $encryptionUtil; | ||||||
|  |  | ||||||
|  |         if (!isset($config['issuer'])) { | ||||||
|  |             throw new \LogicException('config parameter "issuer" must be set'); | ||||||
|  |         } | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'id_lifetime' => 3600, | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $userInfo = null) | ||||||
|  |     { | ||||||
|  |         // build the URL to redirect to | ||||||
|  |         $result = array('query' => array()); | ||||||
|  |         $params += array('scope' => null, 'state' => null, 'nonce' => null); | ||||||
|  |  | ||||||
|  |         // create the id token. | ||||||
|  |         list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo); | ||||||
|  |         $userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']); | ||||||
|  |  | ||||||
|  |         $id_token = $this->createIdToken($params['client_id'], $userInfo, $params['nonce'], $userClaims, null); | ||||||
|  |         $result["fragment"] = array('id_token' => $id_token); | ||||||
|  |         if (isset($params['state'])) { | ||||||
|  |             $result["fragment"]["state"] = $params['state']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array($params['redirect_uri'], $result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null) | ||||||
|  |     { | ||||||
|  |         // pull auth_time from user info if supplied | ||||||
|  |         list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo); | ||||||
|  |  | ||||||
|  |         $token = array( | ||||||
|  |             'iss'        => $this->config['issuer'], | ||||||
|  |             'sub'        => $user_id, | ||||||
|  |             'aud'        => $client_id, | ||||||
|  |             'iat'        => time(), | ||||||
|  |             'exp'        => time() + $this->config['id_lifetime'], | ||||||
|  |             'auth_time'  => $auth_time, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if ($nonce) { | ||||||
|  |             $token['nonce'] = $nonce; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($userClaims) { | ||||||
|  |             $token += $userClaims; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($access_token) { | ||||||
|  |             $token['at_hash'] = $this->createAtHash($access_token, $client_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->encodeToken($token, $client_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createAtHash($access_token, $client_id = null) | ||||||
|  |     { | ||||||
|  |         // maps HS256 and RS256 to sha256, etc. | ||||||
|  |         $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); | ||||||
|  |         $hash_algorithm = 'sha' . substr($algorithm, 2); | ||||||
|  |         $hash = hash($hash_algorithm, $access_token, true); | ||||||
|  |         $at_hash = substr($hash, 0, strlen($hash) / 2); | ||||||
|  |  | ||||||
|  |         return $this->encryptionUtil->urlSafeB64Encode($at_hash); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function encodeToken(array $token, $client_id = null) | ||||||
|  |     { | ||||||
|  |         $private_key = $this->publicKeyStorage->getPrivateKey($client_id); | ||||||
|  |         $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); | ||||||
|  |  | ||||||
|  |         return $this->encryptionUtil->encode($token, $private_key, $algorithm); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getUserIdAndAuthTime($userInfo) | ||||||
|  |     { | ||||||
|  |         $auth_time = null; | ||||||
|  |  | ||||||
|  |         // support an array for user_id / auth_time | ||||||
|  |         if (is_array($userInfo)) { | ||||||
|  |             if (!isset($userInfo['user_id'])) { | ||||||
|  |                 throw new \LogicException('if $user_id argument is an array, user_id index must be set'); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null; | ||||||
|  |             $user_id = $userInfo['user_id']; | ||||||
|  |         } else { | ||||||
|  |             $user_id = $userInfo; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_null($auth_time)) { | ||||||
|  |             $auth_time = time(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // userInfo is a scalar, and so this is the $user_id. Auth Time is null | ||||||
|  |         return array($user_id, $auth_time); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\ResponseTypeInterface; | ||||||
|  |  | ||||||
|  | interface IdTokenInterface extends ResponseTypeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Create the id token. | ||||||
|  |      * | ||||||
|  |      * If Authorization Code Flow is used, the id_token is generated when the | ||||||
|  |      * authorization code is issued, and later returned from the token endpoint | ||||||
|  |      * together with the access_token. | ||||||
|  |      * If the Implicit Flow is used, the token and id_token are generated and | ||||||
|  |      * returned together. | ||||||
|  |      * | ||||||
|  |      * @param string $client_id    The client id. | ||||||
|  |      * @param string $user_id      The user id. | ||||||
|  |      * @param string $nonce        OPTIONAL The nonce. | ||||||
|  |      * @param string $userClaims   OPTIONAL Claims about the user. | ||||||
|  |      * @param string $access_token OPTIONAL The access token, if known. | ||||||
|  |      * | ||||||
|  |      * @return string The ID Token represented as a JSON Web Token (JWT). | ||||||
|  |      * | ||||||
|  |      * @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken | ||||||
|  |      */ | ||||||
|  |     public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null); | ||||||
|  | } | ||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\AccessTokenInterface; | ||||||
|  |  | ||||||
|  | class IdTokenToken implements IdTokenTokenInterface | ||||||
|  | { | ||||||
|  |     protected $accessToken; | ||||||
|  |     protected $idToken; | ||||||
|  |  | ||||||
|  |     public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken) | ||||||
|  |     { | ||||||
|  |         $this->accessToken = $accessToken; | ||||||
|  |         $this->idToken = $idToken; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $result = $this->accessToken->getAuthorizeResponse($params, $user_id); | ||||||
|  |         $access_token = $result[1]['fragment']['access_token']; | ||||||
|  |         $id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token); | ||||||
|  |         $result[1]['fragment']['id_token'] = $id_token; | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\ResponseType\ResponseTypeInterface; | ||||||
|  |  | ||||||
|  | interface IdTokenTokenInterface extends ResponseTypeInterface | ||||||
|  | { | ||||||
|  | } | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\AuthorizationCodeInterface as BaseAuthorizationCodeInterface; | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get/save authorization codes for the "Authorization Code" | ||||||
|  |  * grant type | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Take the provided authorization code values and store them somewhere. | ||||||
|  |      * | ||||||
|  |      * This function should be the storage counterpart to getAuthCode(). | ||||||
|  |      * | ||||||
|  |      * If storage fails for some reason, we're not currently checking for | ||||||
|  |      * any sort of success/failure, so you should bail out of the script | ||||||
|  |      * and provide a descriptive fail message. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_AUTH_CODE. | ||||||
|  |      * | ||||||
|  |      * @param $code                authorization code to be stored. | ||||||
|  |      * @param $client_id           client identifier to be stored. | ||||||
|  |      * @param $user_id             user identifier to be stored. | ||||||
|  |      * @param string $redirect_uri redirect URI(s) to be stored in a space-separated string. | ||||||
|  |      * @param int    $expires      expiration to be stored as a Unix timestamp. | ||||||
|  |      * @param string $scope        OPTIONAL scopes to be stored in space-separated string. | ||||||
|  |      * @param string $id_token     OPTIONAL the OpenID Connect id_token. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null); | ||||||
|  | } | ||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should retrieve user claims for the OpenID Connect id_token. | ||||||
|  |  */ | ||||||
|  | interface UserClaimsInterface | ||||||
|  | { | ||||||
|  |     // valid scope values to pass into the user claims API call | ||||||
|  |     const VALID_CLAIMS = 'profile email address phone'; | ||||||
|  |  | ||||||
|  |     // fields returned for the claims above | ||||||
|  |     const PROFILE_CLAIM_VALUES  = 'name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at'; | ||||||
|  |     const EMAIL_CLAIM_VALUES    = 'email email_verified'; | ||||||
|  |     const ADDRESS_CLAIM_VALUES  = 'formatted street_address locality region postal_code country'; | ||||||
|  |     const PHONE_CLAIM_VALUES    = 'phone_number phone_number_verified'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return claims about the provided user id. | ||||||
|  |      * | ||||||
|  |      * Groups of claims are returned based on the requested scopes. No group | ||||||
|  |      * is required, and no claim is required. | ||||||
|  |      * | ||||||
|  |      * @param $user_id | ||||||
|  |      * The id of the user for which claims should be returned. | ||||||
|  |      * @param $scope | ||||||
|  |      * The requested scope. | ||||||
|  |      * Scopes with matching claims: profile, email, address, phone. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An array in the claim => value format. | ||||||
|  |      * | ||||||
|  |      * @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims | ||||||
|  |      */ | ||||||
|  |     public function getUserClaims($user_id, $scope); | ||||||
|  | } | ||||||
							
								
								
									
										213
									
								
								library/oauth2/src/OAuth2/Request.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								library/oauth2/src/OAuth2/Request.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,213 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * OAuth2\Request | ||||||
|  |  * This class is taken from the Symfony2 Framework and is part of the Symfony package. | ||||||
|  |  * See Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony) | ||||||
|  |  */ | ||||||
|  | class Request implements RequestInterface | ||||||
|  | { | ||||||
|  |     public $attributes; | ||||||
|  |     public $request; | ||||||
|  |     public $query; | ||||||
|  |     public $server; | ||||||
|  |     public $files; | ||||||
|  |     public $cookies; | ||||||
|  |     public $headers; | ||||||
|  |     public $content; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Constructor. | ||||||
|  |      * | ||||||
|  |      * @param array  $query      The GET parameters | ||||||
|  |      * @param array  $request    The POST parameters | ||||||
|  |      * @param array  $attributes The request attributes (parameters parsed from the PATH_INFO, ...) | ||||||
|  |      * @param array  $cookies    The COOKIE parameters | ||||||
|  |      * @param array  $files      The FILES parameters | ||||||
|  |      * @param array  $server     The SERVER parameters | ||||||
|  |      * @param string $content    The raw body data | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null) | ||||||
|  |     { | ||||||
|  |         $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the parameters for this request. | ||||||
|  |      * | ||||||
|  |      * This method also re-initializes all properties. | ||||||
|  |      * | ||||||
|  |      * @param array  $query      The GET parameters | ||||||
|  |      * @param array  $request    The POST parameters | ||||||
|  |      * @param array  $attributes The request attributes (parameters parsed from the PATH_INFO, ...) | ||||||
|  |      * @param array  $cookies    The COOKIE parameters | ||||||
|  |      * @param array  $files      The FILES parameters | ||||||
|  |      * @param array  $server     The SERVER parameters | ||||||
|  |      * @param string $content    The raw body data | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null) | ||||||
|  |     { | ||||||
|  |         $this->request = $request; | ||||||
|  |         $this->query = $query; | ||||||
|  |         $this->attributes = $attributes; | ||||||
|  |         $this->cookies = $cookies; | ||||||
|  |         $this->files = $files; | ||||||
|  |         $this->server = $server; | ||||||
|  |         $this->content = $content; | ||||||
|  |         $this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function query($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->query[$name]) ? $this->query[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function request($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->request[$name]) ? $this->request[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function server($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->server[$name]) ? $this->server[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function headers($name, $default = null) | ||||||
|  |     { | ||||||
|  |         $headers = array_change_key_case($this->headers); | ||||||
|  |         $name = strtolower($name); | ||||||
|  |  | ||||||
|  |         return isset($headers[$name]) ? $headers[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAllQueryParameters() | ||||||
|  |     { | ||||||
|  |         return $this->query; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the request body content. | ||||||
|  |      * | ||||||
|  |      * @param Boolean $asResource If true, a resource will be returned | ||||||
|  |      * | ||||||
|  |      * @return string|resource The request body content or a resource to read the body stream. | ||||||
|  |      */ | ||||||
|  |     public function getContent($asResource = false) | ||||||
|  |     { | ||||||
|  |         if (false === $this->content || (true === $asResource && null !== $this->content)) { | ||||||
|  |             throw new \LogicException('getContent() can only be called once when using the resource return type.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (true === $asResource) { | ||||||
|  |             $this->content = false; | ||||||
|  |  | ||||||
|  |             return fopen('php://input', 'rb'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (null === $this->content) { | ||||||
|  |             $this->content = file_get_contents('php://input'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->content; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getHeadersFromServer($server) | ||||||
|  |     { | ||||||
|  |         $headers = array(); | ||||||
|  |         foreach ($server as $key => $value) { | ||||||
|  |             if (0 === strpos($key, 'HTTP_')) { | ||||||
|  |                 $headers[substr($key, 5)] = $value; | ||||||
|  |             } | ||||||
|  |             // CONTENT_* are not prefixed with HTTP_ | ||||||
|  |             elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) { | ||||||
|  |                 $headers[$key] = $value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($server['PHP_AUTH_USER'])) { | ||||||
|  |             $headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER']; | ||||||
|  |             $headers['PHP_AUTH_PW'] = isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : ''; | ||||||
|  |         } else { | ||||||
|  |             /* | ||||||
|  |              * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default | ||||||
|  |              * For this workaround to work, add this line to your .htaccess file: | ||||||
|  |              * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] | ||||||
|  |              * | ||||||
|  |              * A sample .htaccess file: | ||||||
|  |              * RewriteEngine On | ||||||
|  |              * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] | ||||||
|  |              * RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |              * RewriteRule ^(.*)$ app.php [QSA,L] | ||||||
|  |              */ | ||||||
|  |  | ||||||
|  |             $authorizationHeader = null; | ||||||
|  |             if (isset($server['HTTP_AUTHORIZATION'])) { | ||||||
|  |                 $authorizationHeader = $server['HTTP_AUTHORIZATION']; | ||||||
|  |             } elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) { | ||||||
|  |                 $authorizationHeader = $server['REDIRECT_HTTP_AUTHORIZATION']; | ||||||
|  |             } elseif (function_exists('apache_request_headers')) { | ||||||
|  |                 $requestHeaders = (array) apache_request_headers(); | ||||||
|  |  | ||||||
|  |                 // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization) | ||||||
|  |                 $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders)); | ||||||
|  |  | ||||||
|  |                 if (isset($requestHeaders['Authorization'])) { | ||||||
|  |                     $authorizationHeader = trim($requestHeaders['Authorization']); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (null !== $authorizationHeader) { | ||||||
|  |                 $headers['AUTHORIZATION'] = $authorizationHeader; | ||||||
|  |                 // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic | ||||||
|  |                 if (0 === stripos($authorizationHeader, 'basic')) { | ||||||
|  |                     $exploded = explode(':', base64_decode(substr($authorizationHeader, 6))); | ||||||
|  |                     if (count($exploded) == 2) { | ||||||
|  |                         list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // PHP_AUTH_USER/PHP_AUTH_PW | ||||||
|  |         if (isset($headers['PHP_AUTH_USER'])) { | ||||||
|  |             $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $headers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new request with values from PHP's super globals. | ||||||
|  |      * | ||||||
|  |      * @return Request A new request | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public static function createFromGlobals() | ||||||
|  |     { | ||||||
|  |         $class = get_called_class(); | ||||||
|  |         $request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER); | ||||||
|  |  | ||||||
|  |         $contentType = $request->server('CONTENT_TYPE', ''); | ||||||
|  |         $requestMethod = $request->server('REQUEST_METHOD', 'GET'); | ||||||
|  |         if (0 === strpos($contentType, 'application/x-www-form-urlencoded') | ||||||
|  |             && in_array(strtoupper($requestMethod), array('PUT', 'DELETE')) | ||||||
|  |         ) { | ||||||
|  |             parse_str($request->getContent(), $data); | ||||||
|  |             $request->request = $data; | ||||||
|  |         } elseif (0 === strpos($contentType, 'application/json') | ||||||
|  |             && in_array(strtoupper($requestMethod), array('POST', 'PUT', 'DELETE')) | ||||||
|  |         ) { | ||||||
|  |             $data = json_decode($request->getContent(), true); | ||||||
|  |             $request->request = $data; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $request; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								library/oauth2/src/OAuth2/RequestInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								library/oauth2/src/OAuth2/RequestInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | interface RequestInterface | ||||||
|  | { | ||||||
|  |     public function query($name, $default = null); | ||||||
|  |  | ||||||
|  |     public function request($name, $default = null); | ||||||
|  |  | ||||||
|  |     public function server($name, $default = null); | ||||||
|  |  | ||||||
|  |     public function headers($name, $default = null); | ||||||
|  |  | ||||||
|  |     public function getAllQueryParameters(); | ||||||
|  | } | ||||||
							
								
								
									
										369
									
								
								library/oauth2/src/OAuth2/Response.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								library/oauth2/src/OAuth2/Response.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,369 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class to handle OAuth2 Responses in a graceful way.  Use this interface | ||||||
|  |  * to output the proper OAuth2 responses. | ||||||
|  |  * | ||||||
|  |  * @see OAuth2\ResponseInterface | ||||||
|  |  * | ||||||
|  |  * This class borrows heavily from the Symfony2 Framework and is part of the symfony package | ||||||
|  |  * @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony) | ||||||
|  |  */ | ||||||
|  | class Response implements ResponseInterface | ||||||
|  | { | ||||||
|  |     public $version; | ||||||
|  |     protected $statusCode = 200; | ||||||
|  |     protected $statusText; | ||||||
|  |     protected $parameters = array(); | ||||||
|  |     protected $httpHeaders = array(); | ||||||
|  |  | ||||||
|  |     public static $statusTexts = array( | ||||||
|  |         100 => 'Continue', | ||||||
|  |         101 => 'Switching Protocols', | ||||||
|  |         200 => 'OK', | ||||||
|  |         201 => 'Created', | ||||||
|  |         202 => 'Accepted', | ||||||
|  |         203 => 'Non-Authoritative Information', | ||||||
|  |         204 => 'No Content', | ||||||
|  |         205 => 'Reset Content', | ||||||
|  |         206 => 'Partial Content', | ||||||
|  |         300 => 'Multiple Choices', | ||||||
|  |         301 => 'Moved Permanently', | ||||||
|  |         302 => 'Found', | ||||||
|  |         303 => 'See Other', | ||||||
|  |         304 => 'Not Modified', | ||||||
|  |         305 => 'Use Proxy', | ||||||
|  |         307 => 'Temporary Redirect', | ||||||
|  |         400 => 'Bad Request', | ||||||
|  |         401 => 'Unauthorized', | ||||||
|  |         402 => 'Payment Required', | ||||||
|  |         403 => 'Forbidden', | ||||||
|  |         404 => 'Not Found', | ||||||
|  |         405 => 'Method Not Allowed', | ||||||
|  |         406 => 'Not Acceptable', | ||||||
|  |         407 => 'Proxy Authentication Required', | ||||||
|  |         408 => 'Request Timeout', | ||||||
|  |         409 => 'Conflict', | ||||||
|  |         410 => 'Gone', | ||||||
|  |         411 => 'Length Required', | ||||||
|  |         412 => 'Precondition Failed', | ||||||
|  |         413 => 'Request Entity Too Large', | ||||||
|  |         414 => 'Request-URI Too Long', | ||||||
|  |         415 => 'Unsupported Media Type', | ||||||
|  |         416 => 'Requested Range Not Satisfiable', | ||||||
|  |         417 => 'Expectation Failed', | ||||||
|  |         418 => 'I\'m a teapot', | ||||||
|  |         500 => 'Internal Server Error', | ||||||
|  |         501 => 'Not Implemented', | ||||||
|  |         502 => 'Bad Gateway', | ||||||
|  |         503 => 'Service Unavailable', | ||||||
|  |         504 => 'Gateway Timeout', | ||||||
|  |         505 => 'HTTP Version Not Supported', | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     public function __construct($parameters = array(), $statusCode = 200, $headers = array()) | ||||||
|  |     { | ||||||
|  |         $this->setParameters($parameters); | ||||||
|  |         $this->setStatusCode($statusCode); | ||||||
|  |         $this->setHttpHeaders($headers); | ||||||
|  |         $this->version = '1.1'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Converts the response object to string containing all headers and the response content. | ||||||
|  |      * | ||||||
|  |      * @return string The response with headers and content | ||||||
|  |      */ | ||||||
|  |     public function __toString() | ||||||
|  |     { | ||||||
|  |         $headers = array(); | ||||||
|  |         foreach ($this->httpHeaders as $name => $value) { | ||||||
|  |             $headers[$name] = (array) $value; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return | ||||||
|  |             sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". | ||||||
|  |             $this->getHttpHeadersAsString($headers)."\r\n". | ||||||
|  |             $this->getResponseBody(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the build header line. | ||||||
|  |      * | ||||||
|  |      * @param string $name  The header name | ||||||
|  |      * @param string $value The header value | ||||||
|  |      * | ||||||
|  |      * @return string The built header line | ||||||
|  |      */ | ||||||
|  |     protected function buildHeader($name, $value) | ||||||
|  |     { | ||||||
|  |         return sprintf("%s: %s\n", $name, $value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getStatusCode() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setStatusCode($statusCode, $text = null) | ||||||
|  |     { | ||||||
|  |         $this->statusCode = (int) $statusCode; | ||||||
|  |         if ($this->isInvalid()) { | ||||||
|  |             throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getStatusText() | ||||||
|  |     { | ||||||
|  |         return $this->statusText; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getParameters() | ||||||
|  |     { | ||||||
|  |         return $this->parameters; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setParameters(array $parameters) | ||||||
|  |     { | ||||||
|  |         $this->parameters = $parameters; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function addParameters(array $parameters) | ||||||
|  |     { | ||||||
|  |         $this->parameters = array_merge($this->parameters, $parameters); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getParameter($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->parameters[$name]) ? $this->parameters[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setParameter($name, $value) | ||||||
|  |     { | ||||||
|  |         $this->parameters[$name] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setHttpHeaders(array $httpHeaders) | ||||||
|  |     { | ||||||
|  |         $this->httpHeaders = $httpHeaders; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setHttpHeader($name, $value) | ||||||
|  |     { | ||||||
|  |         $this->httpHeaders[$name] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function addHttpHeaders(array $httpHeaders) | ||||||
|  |     { | ||||||
|  |         $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getHttpHeaders() | ||||||
|  |     { | ||||||
|  |         return $this->httpHeaders; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getHttpHeader($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResponseBody($format = 'json') | ||||||
|  |     { | ||||||
|  |         switch ($format) { | ||||||
|  |             case 'json': | ||||||
|  |                 return json_encode($this->parameters); | ||||||
|  |             case 'xml': | ||||||
|  |                 // this only works for single-level arrays | ||||||
|  |                 $xml = new \SimpleXMLElement('<response/>'); | ||||||
|  |                 foreach ($this->parameters as $key => $param) { | ||||||
|  |                     $xml->addChild($key, $param); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return $xml->asXML(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format)); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function send($format = 'json') | ||||||
|  |     { | ||||||
|  |         // headers have already been sent by the developer | ||||||
|  |         if (headers_sent()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         switch ($format) { | ||||||
|  |             case 'json': | ||||||
|  |                 $this->setHttpHeader('Content-Type', 'application/json'); | ||||||
|  |                 break; | ||||||
|  |             case 'xml': | ||||||
|  |                 $this->setHttpHeader('Content-Type', 'text/xml'); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         // status | ||||||
|  |         header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)); | ||||||
|  |  | ||||||
|  |         foreach ($this->getHttpHeaders() as $name => $header) { | ||||||
|  |             header(sprintf('%s: %s', $name, $header)); | ||||||
|  |         } | ||||||
|  |         echo $this->getResponseBody($format); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setError($statusCode, $error, $errorDescription = null, $errorUri = null) | ||||||
|  |     { | ||||||
|  |         $parameters = array( | ||||||
|  |             'error' => $error, | ||||||
|  |             'error_description' => $errorDescription, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if (!is_null($errorUri)) { | ||||||
|  |             if (strlen($errorUri) > 0 && $errorUri[0] == '#') { | ||||||
|  |                 // we are referencing an oauth bookmark (for brevity) | ||||||
|  |                 $errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri; | ||||||
|  |             } | ||||||
|  |             $parameters['error_uri'] = $errorUri; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $httpHeaders = array( | ||||||
|  |             'Cache-Control' => 'no-store' | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->setStatusCode($statusCode); | ||||||
|  |         $this->addParameters($parameters); | ||||||
|  |         $this->addHttpHeaders($httpHeaders); | ||||||
|  |  | ||||||
|  |         if (!$this->isClientError() && !$this->isServerError()) { | ||||||
|  |             throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null) | ||||||
|  |     { | ||||||
|  |         if (empty($url)) { | ||||||
|  |             throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $parameters = array(); | ||||||
|  |  | ||||||
|  |         if (!is_null($state)) { | ||||||
|  |             $parameters['state'] = $state; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!is_null($error)) { | ||||||
|  |             $this->setError(400, $error, $errorDescription, $errorUri); | ||||||
|  |         } | ||||||
|  |         $this->setStatusCode($statusCode); | ||||||
|  |         $this->addParameters($parameters); | ||||||
|  |  | ||||||
|  |         if (count($this->parameters) > 0) { | ||||||
|  |             // add parameters to URL redirection | ||||||
|  |             $parts = parse_url($url); | ||||||
|  |             $sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?'; | ||||||
|  |             $url .= $sep . http_build_query($this->parameters); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->addHttpHeaders(array('Location' =>  $url)); | ||||||
|  |  | ||||||
|  |         if (!$this->isRedirection()) { | ||||||
|  |             throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isInvalid() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode < 100 || $this->statusCode >= 600; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isInformational() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode >= 100 && $this->statusCode < 200; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isSuccessful() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode >= 200 && $this->statusCode < 300; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isRedirection() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode >= 300 && $this->statusCode < 400; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isClientError() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode >= 400 && $this->statusCode < 500; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Boolean | ||||||
|  |      * | ||||||
|  |      * @api | ||||||
|  |      */ | ||||||
|  |     public function isServerError() | ||||||
|  |     { | ||||||
|  |         return $this->statusCode >= 500 && $this->statusCode < 600; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Functions from Symfony2 HttpFoundation - output pretty header | ||||||
|  |      */ | ||||||
|  |     private function getHttpHeadersAsString($headers) | ||||||
|  |     { | ||||||
|  |         if (count($headers) == 0) { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $max = max(array_map('strlen', array_keys($headers))) + 1; | ||||||
|  |         $content = ''; | ||||||
|  |         ksort($headers); | ||||||
|  |         foreach ($headers as $name => $values) { | ||||||
|  |             foreach ($values as $value) { | ||||||
|  |                 $content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $content; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function beautifyHeaderName($name) | ||||||
|  |     { | ||||||
|  |         return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function beautifyCallback($match) | ||||||
|  |     { | ||||||
|  |         return '-'.strtoupper($match[1]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								library/oauth2/src/OAuth2/ResponseInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								library/oauth2/src/OAuth2/ResponseInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Interface which represents an object response.  Meant to handle and display the proper OAuth2 Responses | ||||||
|  |  * for errors and successes | ||||||
|  |  * | ||||||
|  |  * @see OAuth2\Response | ||||||
|  |  */ | ||||||
|  | interface ResponseInterface | ||||||
|  | { | ||||||
|  |     public function addParameters(array $parameters); | ||||||
|  |  | ||||||
|  |     public function addHttpHeaders(array $httpHeaders); | ||||||
|  |  | ||||||
|  |     public function setStatusCode($statusCode); | ||||||
|  |  | ||||||
|  |     public function setError($statusCode, $name, $description = null, $uri = null); | ||||||
|  |  | ||||||
|  |     public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null); | ||||||
|  |  | ||||||
|  |     public function getParameter($name); | ||||||
|  | } | ||||||
							
								
								
									
										194
									
								
								library/oauth2/src/OAuth2/ResponseType/AccessToken.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								library/oauth2/src/OAuth2/ResponseType/AccessToken.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,194 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface; | ||||||
|  | use OAuth2\Storage\RefreshTokenInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class AccessToken implements AccessTokenInterface | ||||||
|  | { | ||||||
|  |     protected $tokenStorage; | ||||||
|  |     protected $refreshStorage; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Storage\AccessTokenInterface  $tokenStorage   REQUIRED Storage class for saving access token information | ||||||
|  |      * @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information | ||||||
|  |      * @param array                                $config         OPTIONAL Configuration options for the server | ||||||
|  |      *                                                             <code> | ||||||
|  |      *                                                             $config = array( | ||||||
|  |      *                                                             'token_type' => 'bearer',              // token type identifier | ||||||
|  |      *                                                             'access_lifetime' => 3600,             // time before access token expires | ||||||
|  |      *                                                             'refresh_token_lifetime' => 1209600,   // time before refresh token expires | ||||||
|  |      *                                                             ); | ||||||
|  |      *                                                             </endcode> | ||||||
|  |      */ | ||||||
|  |     public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->tokenStorage = $tokenStorage; | ||||||
|  |         $this->refreshStorage = $refreshStorage; | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'token_type'             => 'bearer', | ||||||
|  |             'access_lifetime'        => 3600, | ||||||
|  |             'refresh_token_lifetime' => 1209600, | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null) | ||||||
|  |     { | ||||||
|  |         // build the URL to redirect to | ||||||
|  |         $result = array('query' => array()); | ||||||
|  |  | ||||||
|  |         $params += array('scope' => null, 'state' => null); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * a refresh token MUST NOT be included in the fragment | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6749#section-4.2.2 | ||||||
|  |          */ | ||||||
|  |         $includeRefreshToken = false; | ||||||
|  |         $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken); | ||||||
|  |  | ||||||
|  |         if (isset($params['state'])) { | ||||||
|  |             $result["fragment"]["state"] = $params['state']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array($params['redirect_uri'], $result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of access token, also issue refresh token if supported / desirable. | ||||||
|  |      * | ||||||
|  |      * @param $client_id                client identifier related to the access token. | ||||||
|  |      * @param $user_id                  user ID associated with the access token | ||||||
|  |      * @param $scope                    OPTIONAL scopes to be stored in space-separated string. | ||||||
|  |      * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-5 | ||||||
|  |      * @ingroup oauth2_section_5 | ||||||
|  |      */ | ||||||
|  |     public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) | ||||||
|  |     { | ||||||
|  |         $token = array( | ||||||
|  |             "access_token" => $this->generateAccessToken(), | ||||||
|  |             "expires_in" => $this->config['access_lifetime'], | ||||||
|  |             "token_type" => $this->config['token_type'], | ||||||
|  |             "scope" => $scope | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * Issue a refresh token also, if we support them | ||||||
|  |          * | ||||||
|  |          * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface | ||||||
|  |          * is supplied in the constructor | ||||||
|  |          */ | ||||||
|  |         if ($includeRefreshToken && $this->refreshStorage) { | ||||||
|  |             $token["refresh_token"] = $this->generateRefreshToken(); | ||||||
|  |             $expires = 0; | ||||||
|  |             if ($this->config['refresh_token_lifetime'] > 0) { | ||||||
|  |                 $expires = time() + $this->config['refresh_token_lifetime']; | ||||||
|  |             } | ||||||
|  |             $this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Generates an unique access token. | ||||||
|  |      * | ||||||
|  |      * Implementing classes may want to override this function to implement | ||||||
|  |      * other access token generation schemes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An unique access token. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     protected function generateAccessToken() | ||||||
|  |     { | ||||||
|  |         if (function_exists('mcrypt_create_iv')) { | ||||||
|  |             $randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM); | ||||||
|  |             if ($randomData !== false && strlen($randomData) === 20) { | ||||||
|  |                 return bin2hex($randomData); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (function_exists('openssl_random_pseudo_bytes')) { | ||||||
|  |             $randomData = openssl_random_pseudo_bytes(20); | ||||||
|  |             if ($randomData !== false && strlen($randomData) === 20) { | ||||||
|  |                 return bin2hex($randomData); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data | ||||||
|  |             $randomData = file_get_contents('/dev/urandom', false, null, 0, 20); | ||||||
|  |             if ($randomData !== false && strlen($randomData) === 20) { | ||||||
|  |                 return bin2hex($randomData); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Last resort which you probably should just get rid of: | ||||||
|  |         $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); | ||||||
|  |  | ||||||
|  |         return substr(hash('sha512', $randomData), 0, 40); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Generates an unique refresh token | ||||||
|  |      * | ||||||
|  |      * Implementing classes may want to override this function to implement | ||||||
|  |      * other refresh token generation schemes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An unique refresh. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      * @see OAuth2::generateAccessToken() | ||||||
|  |      */ | ||||||
|  |     protected function generateRefreshToken() | ||||||
|  |     { | ||||||
|  |         return $this->generateAccessToken(); // let's reuse the same scheme for token generation | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the revoking of refresh tokens, and access tokens if supported / desirable | ||||||
|  |      * RFC7009 specifies that "If the server is unable to locate the token using | ||||||
|  |      * the given hint, it MUST extend its search across all of its supported token types" | ||||||
|  |      * | ||||||
|  |      * @param $token | ||||||
|  |      * @param null $tokenTypeHint | ||||||
|  |      * @return boolean | ||||||
|  |      */ | ||||||
|  |     public function revokeToken($token, $tokenTypeHint = null) | ||||||
|  |     { | ||||||
|  |         if ($tokenTypeHint == 'refresh_token') { | ||||||
|  |             if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** @TODO remove in v2 */ | ||||||
|  |         if (!method_exists($this->tokenStorage, 'unsetAccessToken')) { | ||||||
|  |             throw new \RuntimeException( | ||||||
|  |                 sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage) | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $revoked = $this->tokenStorage->unsetAccessToken($token); | ||||||
|  |  | ||||||
|  |         // if a typehint is supplied and fails, try other storages  | ||||||
|  |         // @see https://tools.ietf.org/html/rfc7009#section-2.1 | ||||||
|  |         if (!$revoked && $tokenTypeHint != 'refresh_token') { | ||||||
|  |             if ($this->refreshStorage) { | ||||||
|  |                 $revoked = $this->refreshStorage->unsetRefreshToken($token); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $revoked; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,34 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AccessTokenInterface extends ResponseTypeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of access token, also issue refresh token if supported / desirable. | ||||||
|  |      * | ||||||
|  |      * @param $client_id                client identifier related to the access token. | ||||||
|  |      * @param $user_id                  user ID associated with the access token | ||||||
|  |      * @param $scope                    OPTONAL scopes to be stored in space-separated string. | ||||||
|  |      * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-5 | ||||||
|  |      * @ingroup oauth2_section_5 | ||||||
|  |      */ | ||||||
|  |     public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the revoking of refresh tokens, and access tokens if supported / desirable | ||||||
|  |      * | ||||||
|  |      * @param $token | ||||||
|  |      * @param $tokenTypeHint | ||||||
|  |      * @return mixed | ||||||
|  |      * | ||||||
|  |      * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x | ||||||
|  |      */ | ||||||
|  |     //public function revokeToken($token, $tokenTypeHint); | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class AuthorizationCode implements AuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     protected $storage; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->storage = $storage; | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'enforce_redirect' => false, | ||||||
|  |             'auth_code_lifetime' => 30, | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null) | ||||||
|  |     { | ||||||
|  |         // build the URL to redirect to | ||||||
|  |         $result = array('query' => array()); | ||||||
|  |  | ||||||
|  |         $params += array('scope' => null, 'state' => null); | ||||||
|  |  | ||||||
|  |         $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']); | ||||||
|  |  | ||||||
|  |         if (isset($params['state'])) { | ||||||
|  |             $result['query']['state'] = $params['state']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array($params['redirect_uri'], $result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of the authorization code. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier related to the authorization code | ||||||
|  |      * @param $user_id | ||||||
|  |      * User ID associated with the authorization code | ||||||
|  |      * @param $redirect_uri | ||||||
|  |      * An absolute URI to which the authorization server will redirect the | ||||||
|  |      * user-agent to when the end-user authorization step is completed. | ||||||
|  |      * @param $scope | ||||||
|  |      * (optional) Scopes to be stored in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null) | ||||||
|  |     { | ||||||
|  |         $code = $this->generateAuthorizationCode(); | ||||||
|  |         $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope); | ||||||
|  |  | ||||||
|  |         return $code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the grant type requires a redirect_uri, FALSE if not | ||||||
|  |      */ | ||||||
|  |     public function enforceRedirect() | ||||||
|  |     { | ||||||
|  |         return $this->config['enforce_redirect']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Generates an unique auth code. | ||||||
|  |      * | ||||||
|  |      * Implementing classes may want to override this function to implement | ||||||
|  |      * other auth code generation schemes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An unique auth code. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     protected function generateAuthorizationCode() | ||||||
|  |     { | ||||||
|  |         $tokenLen = 40; | ||||||
|  |         if (function_exists('mcrypt_create_iv')) { | ||||||
|  |             $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM); | ||||||
|  |         } elseif (function_exists('openssl_random_pseudo_bytes')) { | ||||||
|  |             $randomData = openssl_random_pseudo_bytes(100); | ||||||
|  |         } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data | ||||||
|  |             $randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true); | ||||||
|  |         } else { | ||||||
|  |             $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return substr(hash('sha512', $randomData), 0, $tokenLen); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,30 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AuthorizationCodeInterface extends ResponseTypeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the grant type requires a redirect_uri, FALSE if not | ||||||
|  |      */ | ||||||
|  |     public function enforceRedirect(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of the authorization code. | ||||||
|  |      * | ||||||
|  |      * @param $client_id    client identifier related to the authorization code | ||||||
|  |      * @param $user_id      user id associated with the authorization code | ||||||
|  |      * @param $redirect_uri an absolute URI to which the authorization server will redirect the | ||||||
|  |      *                      user-agent to when the end-user authorization step is completed. | ||||||
|  |      * @param $scope        OPTIONAL scopes to be stored in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null); | ||||||
|  | } | ||||||
							
								
								
									
										124
									
								
								library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Encryption\EncryptionInterface; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  | use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface; | ||||||
|  | use OAuth2\Storage\RefreshTokenInterface; | ||||||
|  | use OAuth2\Storage\PublicKeyInterface; | ||||||
|  | use OAuth2\Storage\Memory; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class JwtAccessToken extends AccessToken | ||||||
|  | { | ||||||
|  |     protected $publicKeyStorage; | ||||||
|  |     protected $encryptionUtil; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param $config | ||||||
|  |      *  - store_encrypted_token_string (bool true) | ||||||
|  |      *       whether the entire encrypted string is stored, | ||||||
|  |      *       or just the token ID is stored | ||||||
|  |      */ | ||||||
|  |     public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->publicKeyStorage = $publicKeyStorage; | ||||||
|  |         $config = array_merge(array( | ||||||
|  |             'store_encrypted_token_string' => true, | ||||||
|  |             'issuer' => '' | ||||||
|  |         ), $config); | ||||||
|  |         if (is_null($tokenStorage)) { | ||||||
|  |             // a pass-thru, so we can call the parent constructor | ||||||
|  |             $tokenStorage = new Memory(); | ||||||
|  |         } | ||||||
|  |         if (is_null($encryptionUtil)) { | ||||||
|  |             $encryptionUtil = new Jwt(); | ||||||
|  |         } | ||||||
|  |         $this->encryptionUtil = $encryptionUtil; | ||||||
|  |         parent::__construct($tokenStorage, $refreshStorage, $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the creation of access token, also issue refresh token if supported / desirable. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier related to the access token. | ||||||
|  |      * @param $user_id | ||||||
|  |      * User ID associated with the access token | ||||||
|  |      * @param $scope | ||||||
|  |      * (optional) Scopes to be stored in space-separated string. | ||||||
|  |      * @param bool $includeRefreshToken | ||||||
|  |      *                                  If true, a new refresh_token will be added to the response | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-5 | ||||||
|  |      * @ingroup oauth2_section_5 | ||||||
|  |      */ | ||||||
|  |     public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) | ||||||
|  |     { | ||||||
|  |         // token to encrypt | ||||||
|  |         $expires = time() + $this->config['access_lifetime']; | ||||||
|  |         $id = $this->generateAccessToken(); | ||||||
|  |         $jwtAccessToken = array( | ||||||
|  |             'id'         => $id, // for BC (see #591) | ||||||
|  |             'jti'        => $id, | ||||||
|  |             'iss'        => $this->config['issuer'], | ||||||
|  |             'aud'        => $client_id, | ||||||
|  |             'sub'        => $user_id, | ||||||
|  |             'exp'        => $expires, | ||||||
|  |             'iat'        => time(), | ||||||
|  |             'token_type' => $this->config['token_type'], | ||||||
|  |             'scope'      => $scope | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * Encode the token data into a single access_token string | ||||||
|  |          */ | ||||||
|  |         $access_token = $this->encodeToken($jwtAccessToken, $client_id); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * Save the token to a secondary storage.  This is implemented on the | ||||||
|  |          * OAuth2\Storage\JwtAccessToken side, and will not actually store anything, | ||||||
|  |          * if no secondary storage has been supplied | ||||||
|  |          */ | ||||||
|  |         $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id']; | ||||||
|  |         $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); | ||||||
|  |  | ||||||
|  |         // token to return to the client | ||||||
|  |         $token = array( | ||||||
|  |             'access_token' => $access_token, | ||||||
|  |             'expires_in' => $this->config['access_lifetime'], | ||||||
|  |             'token_type' => $this->config['token_type'], | ||||||
|  |             'scope' => $scope | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * Issue a refresh token also, if we support them | ||||||
|  |          * | ||||||
|  |          * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface | ||||||
|  |          * is supplied in the constructor | ||||||
|  |          */ | ||||||
|  |         if ($includeRefreshToken && $this->refreshStorage) { | ||||||
|  |             $refresh_token = $this->generateRefreshToken(); | ||||||
|  |             $expires = 0; | ||||||
|  |             if ($this->config['refresh_token_lifetime'] > 0) { | ||||||
|  |                 $expires = time() + $this->config['refresh_token_lifetime']; | ||||||
|  |             } | ||||||
|  |             $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope); | ||||||
|  |             $token['refresh_token'] = $refresh_token; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function encodeToken(array $token, $client_id = null) | ||||||
|  |     { | ||||||
|  |         $private_key = $this->publicKeyStorage->getPrivateKey($client_id); | ||||||
|  |         $algorithm   = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); | ||||||
|  |  | ||||||
|  |         return $this->encryptionUtil->encode($token, $private_key, $algorithm); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | interface ResponseTypeInterface | ||||||
|  | { | ||||||
|  |     public function getAuthorizeResponse($params, $user_id = null); | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								library/oauth2/src/OAuth2/Scope.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								library/oauth2/src/OAuth2/Scope.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Memory; | ||||||
|  | use OAuth2\Storage\ScopeInterface as ScopeStorageInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | * @see OAuth2\ScopeInterface | ||||||
|  | */ | ||||||
|  | class Scope implements ScopeInterface | ||||||
|  | { | ||||||
|  |     protected $storage; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param mixed @storage | ||||||
|  |      * Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface | ||||||
|  |      */ | ||||||
|  |     public function __construct($storage = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($storage) || is_array($storage)) { | ||||||
|  |             $storage = new Memory((array) $storage); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$storage instanceof ScopeStorageInterface) { | ||||||
|  |             throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->storage = $storage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if everything in required scope is contained in available scope. | ||||||
|  |      * | ||||||
|  |      * @param $required_scope | ||||||
|  |      * A space-separated string of scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if everything in required scope is contained in available scope, | ||||||
|  |      * and FALSE if it isn't. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-7 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_7 | ||||||
|  |      */ | ||||||
|  |     public function checkScope($required_scope, $available_scope) | ||||||
|  |     { | ||||||
|  |         $required_scope = explode(' ', trim($required_scope)); | ||||||
|  |         $available_scope = explode(' ', trim($available_scope)); | ||||||
|  |  | ||||||
|  |         return (count(array_diff($required_scope, $available_scope)) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if the provided scope exists in storage. | ||||||
|  |      * | ||||||
|  |      * @param $scope | ||||||
|  |      * A space-separated string of scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if it exists, FALSE otherwise. | ||||||
|  |      */ | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         // Check reserved scopes first. | ||||||
|  |         $scope = explode(' ', trim($scope)); | ||||||
|  |         $reservedScope = $this->getReservedScopes(); | ||||||
|  |         $nonReservedScopes = array_diff($scope, $reservedScope); | ||||||
|  |         if (count($nonReservedScopes) == 0) { | ||||||
|  |             return true; | ||||||
|  |         } else { | ||||||
|  |             // Check the storage for non-reserved scopes. | ||||||
|  |             $nonReservedScopes = implode(' ', $nonReservedScopes); | ||||||
|  |  | ||||||
|  |             return $this->storage->scopeExists($nonReservedScopes); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScopeFromRequest(RequestInterface $request) | ||||||
|  |     { | ||||||
|  |         // "scope" is valid if passed in either POST or QUERY | ||||||
|  |         return $request->request('scope', $request->query('scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |         return $this->storage->getDefaultScope($client_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get reserved scopes needed by the server. | ||||||
|  |      * | ||||||
|  |      * In case OpenID Connect is used, these scopes must include: | ||||||
|  |      * 'openid', offline_access'. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An array of reserved scopes. | ||||||
|  |      */ | ||||||
|  |     public function getReservedScopes() | ||||||
|  |     { | ||||||
|  |         return array('openid', 'offline_access'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								library/oauth2/src/OAuth2/ScopeInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								library/oauth2/src/OAuth2/ScopeInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\ScopeInterface as ScopeStorageInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class to handle scope implementation logic | ||||||
|  |  * | ||||||
|  |  * @see OAuth2\Storage\ScopeInterface | ||||||
|  |  */ | ||||||
|  | interface ScopeInterface extends ScopeStorageInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Check if everything in required scope is contained in available scope. | ||||||
|  |      * | ||||||
|  |      * @param $required_scope | ||||||
|  |      * A space-separated string of scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if everything in required scope is contained in available scope, | ||||||
|  |      * and FALSE if it isn't. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-7 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_7 | ||||||
|  |      */ | ||||||
|  |     public function checkScope($required_scope, $available_scope); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return scope info from request | ||||||
|  |      * | ||||||
|  |      * @param OAuth2\RequestInterface | ||||||
|  |      * Request object to check | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * string representation of requested scope | ||||||
|  |      */ | ||||||
|  |     public function getScopeFromRequest(RequestInterface $request); | ||||||
|  | } | ||||||
							
								
								
									
										832
									
								
								library/oauth2/src/OAuth2/Server.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										832
									
								
								library/oauth2/src/OAuth2/Server.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,832 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Controller\ResourceControllerInterface; | ||||||
|  | use OAuth2\Controller\ResourceController; | ||||||
|  | use OAuth2\OpenID\Controller\UserInfoControllerInterface; | ||||||
|  | use OAuth2\OpenID\Controller\UserInfoController; | ||||||
|  | use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController; | ||||||
|  | use OAuth2\OpenID\ResponseType\AuthorizationCode as OpenIDAuthorizationCodeResponseType; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  | use OAuth2\OpenID\GrantType\AuthorizationCode as OpenIDAuthorizationCodeGrantType; | ||||||
|  | use OAuth2\Controller\AuthorizeControllerInterface; | ||||||
|  | use OAuth2\Controller\AuthorizeController; | ||||||
|  | use OAuth2\Controller\TokenControllerInterface; | ||||||
|  | use OAuth2\Controller\TokenController; | ||||||
|  | use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; | ||||||
|  | use OAuth2\ClientAssertionType\HttpBasic; | ||||||
|  | use OAuth2\ResponseType\ResponseTypeInterface; | ||||||
|  | use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType; | ||||||
|  | use OAuth2\ResponseType\AccessToken; | ||||||
|  | use OAuth2\ResponseType\JwtAccessToken; | ||||||
|  | use OAuth2\OpenID\ResponseType\CodeIdToken; | ||||||
|  | use OAuth2\OpenID\ResponseType\IdToken; | ||||||
|  | use OAuth2\OpenID\ResponseType\IdTokenToken; | ||||||
|  | use OAuth2\TokenType\TokenTypeInterface; | ||||||
|  | use OAuth2\TokenType\Bearer; | ||||||
|  | use OAuth2\GrantType\GrantTypeInterface; | ||||||
|  | use OAuth2\GrantType\UserCredentials; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  | use OAuth2\GrantType\RefreshToken; | ||||||
|  | use OAuth2\GrantType\AuthorizationCode; | ||||||
|  | use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage; | ||||||
|  | use OAuth2\Storage\JwtAccessTokenInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | * Server class for OAuth2 | ||||||
|  | * This class serves as a convience class which wraps the other Controller classes | ||||||
|  | * | ||||||
|  | * @see OAuth2\Controller\ResourceController | ||||||
|  | * @see OAuth2\Controller\AuthorizeController | ||||||
|  | * @see OAuth2\Controller\TokenController | ||||||
|  | */ | ||||||
|  | class Server implements ResourceControllerInterface, | ||||||
|  |     AuthorizeControllerInterface, | ||||||
|  |     TokenControllerInterface, | ||||||
|  |     UserInfoControllerInterface | ||||||
|  | { | ||||||
|  |     // misc properties | ||||||
|  |     protected $response; | ||||||
|  |     protected $config; | ||||||
|  |     protected $storages; | ||||||
|  |  | ||||||
|  |     // servers | ||||||
|  |     protected $authorizeController; | ||||||
|  |     protected $tokenController; | ||||||
|  |     protected $resourceController; | ||||||
|  |     protected $userInfoController; | ||||||
|  |  | ||||||
|  |     // config classes | ||||||
|  |     protected $grantTypes; | ||||||
|  |     protected $responseTypes; | ||||||
|  |     protected $tokenType; | ||||||
|  |     protected $scopeUtil; | ||||||
|  |     protected $clientAssertionType; | ||||||
|  |  | ||||||
|  |     protected $storageMap = array( | ||||||
|  |         'access_token' => 'OAuth2\Storage\AccessTokenInterface', | ||||||
|  |         'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface', | ||||||
|  |         'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface', | ||||||
|  |         'client' => 'OAuth2\Storage\ClientInterface', | ||||||
|  |         'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface', | ||||||
|  |         'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface', | ||||||
|  |         'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface', | ||||||
|  |         'public_key' => 'OAuth2\Storage\PublicKeyInterface', | ||||||
|  |         'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface', | ||||||
|  |         'scope' => 'OAuth2\Storage\ScopeInterface', | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     protected $responseTypeMap = array( | ||||||
|  |         'token' => 'OAuth2\ResponseType\AccessTokenInterface', | ||||||
|  |         'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface', | ||||||
|  |         'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface', | ||||||
|  |         'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface', | ||||||
|  |         'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface', | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param mixed                                                   $storage             (array or OAuth2\Storage) - single object or array of objects implementing the | ||||||
|  |      *                                                                                     required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum) | ||||||
|  |      * @param array                                                   $config              specify a different token lifetime, token header name, etc | ||||||
|  |      * @param array                                                   $grantTypes          An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens | ||||||
|  |      * @param array                                                   $responseTypes       Response types to use.  array keys should be "code" and and "token" for | ||||||
|  |      *                                                                                     Access Token and Authorization Code response types | ||||||
|  |      * @param OAuth2\TokenType\TokenTypeInterface                     $tokenType           The token type object to use. Valid token types are "bearer" and "mac" | ||||||
|  |      * @param OAuth2\ScopeInterface                                   $scopeUtil           The scope utility class to use to validate scope | ||||||
|  |      * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity.  Default is HttpBasic | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_7 | ||||||
|  |      */ | ||||||
|  |     public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null) | ||||||
|  |     { | ||||||
|  |         $storage = is_array($storage) ? $storage : array($storage); | ||||||
|  |         $this->storages = array(); | ||||||
|  |         foreach ($storage as $key => $service) { | ||||||
|  |             $this->addStorage($service, $key); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // merge all config values.  These get passed to our controller objects | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'use_jwt_access_tokens'        => false, | ||||||
|  |             'store_encrypted_token_string' => true, | ||||||
|  |             'use_openid_connect'       => false, | ||||||
|  |             'id_lifetime'              => 3600, | ||||||
|  |             'access_lifetime'          => 3600, | ||||||
|  |             'www_realm'                => 'Service', | ||||||
|  |             'token_param_name'         => 'access_token', | ||||||
|  |             'token_bearer_header_name' => 'Bearer', | ||||||
|  |             'enforce_state'            => true, | ||||||
|  |             'require_exact_redirect_uri' => true, | ||||||
|  |             'allow_implicit'           => false, | ||||||
|  |             'allow_credentials_in_request_body' => true, | ||||||
|  |             'allow_public_clients'     => true, | ||||||
|  |             'always_issue_new_refresh_token' => false, | ||||||
|  |             'unset_refresh_token_after_use' => true, | ||||||
|  |         ), $config); | ||||||
|  |  | ||||||
|  |         foreach ($grantTypes as $key => $grantType) { | ||||||
|  |             $this->addGrantType($grantType, $key); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach ($responseTypes as $key => $responseType) { | ||||||
|  |             $this->addResponseType($responseType, $key); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->tokenType = $tokenType; | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |         $this->clientAssertionType = $clientAssertionType; | ||||||
|  |  | ||||||
|  |         if ($this->config['use_openid_connect']) { | ||||||
|  |             $this->validateOpenIdConnect(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAuthorizeController() | ||||||
|  |     { | ||||||
|  |         if (is_null($this->authorizeController)) { | ||||||
|  |             $this->authorizeController = $this->createDefaultAuthorizeController(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->authorizeController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getTokenController() | ||||||
|  |     { | ||||||
|  |         if (is_null($this->tokenController)) { | ||||||
|  |             $this->tokenController = $this->createDefaultTokenController(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->tokenController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResourceController() | ||||||
|  |     { | ||||||
|  |         if (is_null($this->resourceController)) { | ||||||
|  |             $this->resourceController = $this->createDefaultResourceController(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->resourceController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserInfoController() | ||||||
|  |     { | ||||||
|  |         if (is_null($this->userInfoController)) { | ||||||
|  |             $this->userInfoController = $this->createDefaultUserInfoController(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->userInfoController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * every getter deserves a setter | ||||||
|  |      */ | ||||||
|  |     public function setAuthorizeController(AuthorizeControllerInterface $authorizeController) | ||||||
|  |     { | ||||||
|  |         $this->authorizeController = $authorizeController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * every getter deserves a setter | ||||||
|  |      */ | ||||||
|  |     public function setTokenController(TokenControllerInterface $tokenController) | ||||||
|  |     { | ||||||
|  |         $this->tokenController = $tokenController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * every getter deserves a setter | ||||||
|  |      */ | ||||||
|  |     public function setResourceController(ResourceControllerInterface $resourceController) | ||||||
|  |     { | ||||||
|  |         $this->resourceController = $resourceController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * every getter deserves a setter | ||||||
|  |      */ | ||||||
|  |     public function setUserInfoController(UserInfoControllerInterface $userInfoController) | ||||||
|  |     { | ||||||
|  |         $this->userInfoController = $userInfoController; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Return claims about the authenticated end-user. | ||||||
|  |      * This would be called from the "/UserInfo" endpoint as defined in the spec. | ||||||
|  |      * | ||||||
|  |      * @param $request - OAuth2\RequestInterface | ||||||
|  |      * Request object to grant access token | ||||||
|  |      * | ||||||
|  |      * @param $response - OAuth2\ResponseInterface | ||||||
|  |      * Response object containing error messages (failure) or user claims (success) | ||||||
|  |      * | ||||||
|  |      * @throws InvalidArgumentException | ||||||
|  |      * @throws LogicException | ||||||
|  |      * | ||||||
|  |      * @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo | ||||||
|  |      */ | ||||||
|  |     public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $this->getUserInfoController()->handleUserInfoRequest($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $this->response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Grant or deny a requested access token. | ||||||
|  |      * This would be called from the "/token" endpoint as defined in the spec. | ||||||
|  |      * Obviously, you can call your endpoint whatever you want. | ||||||
|  |      * | ||||||
|  |      * @param $request - OAuth2\RequestInterface | ||||||
|  |      * Request object to grant access token | ||||||
|  |      * | ||||||
|  |      * @param $response - OAuth2\ResponseInterface | ||||||
|  |      * Response object containing error messages (failure) or access token (success) | ||||||
|  |      * | ||||||
|  |      * @throws InvalidArgumentException | ||||||
|  |      * @throws LogicException | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-10.6 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $this->getTokenController()->handleTokenRequest($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $this->response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $value = $this->getTokenController()->grantAccessToken($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle a revoke token request | ||||||
|  |      * This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec | ||||||
|  |      * | ||||||
|  |      * @see https://tools.ietf.org/html/rfc7009#section-2 | ||||||
|  |      * | ||||||
|  |      * @param RequestInterface $request | ||||||
|  |      * @param ResponseInterface $response | ||||||
|  |      * @return Response|ResponseInterface | ||||||
|  |      */ | ||||||
|  |     public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $this->getTokenController()->handleRevokeRequest($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $this->response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Redirect the user appropriately after approval. | ||||||
|  |      * | ||||||
|  |      * After the user has approved or denied the resource request the | ||||||
|  |      * authorization server should call this function to redirect the user | ||||||
|  |      * appropriately. | ||||||
|  |      * | ||||||
|  |      * @param $request | ||||||
|  |      * The request should have the follow parameters set in the querystring: | ||||||
|  |      * - response_type: The requested response: an access token, an | ||||||
|  |      * authorization code, or both. | ||||||
|  |      * - client_id: The client identifier as described in Section 2. | ||||||
|  |      * - redirect_uri: An absolute URI to which the authorization server | ||||||
|  |      * will redirect the user-agent to when the end-user authorization | ||||||
|  |      * step is completed. | ||||||
|  |      * - scope: (optional) The scope of the resource request expressed as a | ||||||
|  |      * list of space-delimited strings. | ||||||
|  |      * - state: (optional) An opaque value used by the client to maintain | ||||||
|  |      * state between the request and callback. | ||||||
|  |      * @param $is_authorized | ||||||
|  |      * TRUE or FALSE depending on whether the user authorized the access. | ||||||
|  |      * @param $user_id | ||||||
|  |      * Identifier of user who authorized the client | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $this->response = $response; | ||||||
|  |         $this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id); | ||||||
|  |  | ||||||
|  |         return $this->response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Pull the authorization request data out of the HTTP request. | ||||||
|  |      * - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it | ||||||
|  |      * by setting $config['enforce_redirect'] to true. | ||||||
|  |      * - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that | ||||||
|  |      * CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true. | ||||||
|  |      * | ||||||
|  |      * The draft specifies that the parameters should be retrieved from GET, override the Response | ||||||
|  |      * object to change this | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * The authorization parameters so the authorization server can prompt | ||||||
|  |      * the user for approval if valid. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.1 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-10.12 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_3 | ||||||
|  |      */ | ||||||
|  |     public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope); | ||||||
|  |  | ||||||
|  |         return $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null) | ||||||
|  |     { | ||||||
|  |         $this->response = is_null($response) ? new Response() : $response; | ||||||
|  |         $value = $this->getResourceController()->getAccessTokenData($request, $this->response); | ||||||
|  |  | ||||||
|  |         return $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function addGrantType(GrantTypeInterface $grantType, $identifier = null) | ||||||
|  |     { | ||||||
|  |         if (!is_string($identifier)) { | ||||||
|  |             $identifier = $grantType->getQuerystringIdentifier(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->grantTypes[$identifier] = $grantType; | ||||||
|  |  | ||||||
|  |         // persist added grant type down to TokenController | ||||||
|  |         if (!is_null($this->tokenController)) { | ||||||
|  |             $this->getTokenController()->addGrantType($grantType, $identifier); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set a storage object for the server | ||||||
|  |      * | ||||||
|  |      * @param $storage | ||||||
|  |      * An object implementing one of the Storage interfaces | ||||||
|  |      * @param $key | ||||||
|  |      * If null, the storage is set to the key of each storage interface it implements | ||||||
|  |      * | ||||||
|  |      * @see storageMap | ||||||
|  |      */ | ||||||
|  |     public function addStorage($storage, $key = null) | ||||||
|  |     { | ||||||
|  |         // if explicitly set to a valid key, do not "magically" set below | ||||||
|  |         if (isset($this->storageMap[$key])) { | ||||||
|  |             if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) { | ||||||
|  |                 throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key])); | ||||||
|  |             } | ||||||
|  |             $this->storages[$key] = $storage; | ||||||
|  |  | ||||||
|  |             // special logic to handle "client" and "client_credentials" strangeness | ||||||
|  |             if ($key === 'client' && !isset($this->storages['client_credentials'])) { | ||||||
|  |                 if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) { | ||||||
|  |                     $this->storages['client_credentials'] = $storage; | ||||||
|  |                 } | ||||||
|  |             } elseif ($key === 'client_credentials' && !isset($this->storages['client'])) { | ||||||
|  |                 if ($storage instanceof \OAuth2\Storage\ClientInterface) { | ||||||
|  |                     $this->storages['client'] = $storage; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } elseif (!is_null($key) && !is_numeric($key)) { | ||||||
|  |             throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap)))); | ||||||
|  |         } else { | ||||||
|  |             $set = false; | ||||||
|  |             foreach ($this->storageMap as $type => $interface) { | ||||||
|  |                 if ($storage instanceof $interface) { | ||||||
|  |                     $this->storages[$type] = $storage; | ||||||
|  |                     $set = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!$set) { | ||||||
|  |                 throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function addResponseType(ResponseTypeInterface $responseType, $key = null) | ||||||
|  |     { | ||||||
|  |         $key = $this->normalizeResponseType($key); | ||||||
|  |  | ||||||
|  |         if (isset($this->responseTypeMap[$key])) { | ||||||
|  |             if (!$responseType instanceof $this->responseTypeMap[$key]) { | ||||||
|  |                 throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key])); | ||||||
|  |             } | ||||||
|  |             $this->responseTypes[$key] = $responseType; | ||||||
|  |         } elseif (!is_null($key) && !is_numeric($key)) { | ||||||
|  |             throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap)))); | ||||||
|  |         } else { | ||||||
|  |             $set = false; | ||||||
|  |             foreach ($this->responseTypeMap as $type => $interface) { | ||||||
|  |                 if ($responseType instanceof $interface) { | ||||||
|  |                     $this->responseTypes[$type] = $responseType; | ||||||
|  |                     $set = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!$set) { | ||||||
|  |                 throw new \InvalidArgumentException(sprintf('Unknown response type %s.  Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getScopeUtil() | ||||||
|  |     { | ||||||
|  |         if (!$this->scopeUtil) { | ||||||
|  |             $storage = isset($this->storages['scope']) ? $this->storages['scope'] : null; | ||||||
|  |             $this->scopeUtil = new Scope($storage); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * every getter deserves a setter | ||||||
|  |      */ | ||||||
|  |     public function setScopeUtil($scopeUtil) | ||||||
|  |     { | ||||||
|  |         $this->scopeUtil = $scopeUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultAuthorizeController() | ||||||
|  |     { | ||||||
|  |         if (!isset($this->storages['client'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server"); | ||||||
|  |         } | ||||||
|  |         if (0 == count($this->responseTypes)) { | ||||||
|  |             $this->responseTypes = $this->getDefaultResponseTypes(); | ||||||
|  |         } | ||||||
|  |         if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) { | ||||||
|  |             $this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType(); | ||||||
|  |             if ($this->config['allow_implicit']) { | ||||||
|  |                 $this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri'))); | ||||||
|  |  | ||||||
|  |         if ($this->config['use_openid_connect']) { | ||||||
|  |             return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultTokenController() | ||||||
|  |     { | ||||||
|  |         if (0 == count($this->grantTypes)) { | ||||||
|  |             $this->grantTypes = $this->getDefaultGrantTypes(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_null($this->clientAssertionType)) { | ||||||
|  |             // see if HttpBasic assertion type is requred.  If so, then create it from storage classes. | ||||||
|  |             foreach ($this->grantTypes as $grantType) { | ||||||
|  |                 if (!$grantType instanceof ClientAssertionTypeInterface) { | ||||||
|  |                     if (!isset($this->storages['client_credentials'])) { | ||||||
|  |                         throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server"); | ||||||
|  |                     } | ||||||
|  |                     $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients'))); | ||||||
|  |                     $this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($this->storages['client'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $accessTokenResponseType = $this->getAccessTokenResponseType(); | ||||||
|  |  | ||||||
|  |         return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultResourceController() | ||||||
|  |     { | ||||||
|  |         if ($this->config['use_jwt_access_tokens']) { | ||||||
|  |             // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set | ||||||
|  |             if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { | ||||||
|  |                 $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); | ||||||
|  |             } | ||||||
|  |         } elseif (!isset($this->storages['access_token'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->tokenType) { | ||||||
|  |             $this->tokenType = $this->getDefaultTokenType(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array('www_realm' => '')); | ||||||
|  |  | ||||||
|  |         return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultUserInfoController() | ||||||
|  |     { | ||||||
|  |         if ($this->config['use_jwt_access_tokens']) { | ||||||
|  |             // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set | ||||||
|  |             if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { | ||||||
|  |                 $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); | ||||||
|  |             } | ||||||
|  |         } elseif (!isset($this->storages['access_token'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isset($this->storages['user_claims'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->tokenType) { | ||||||
|  |             $this->tokenType = $this->getDefaultTokenType(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array('www_realm' => '')); | ||||||
|  |  | ||||||
|  |         return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getDefaultTokenType() | ||||||
|  |     { | ||||||
|  |         $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name'))); | ||||||
|  |  | ||||||
|  |         return new Bearer($config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getDefaultResponseTypes() | ||||||
|  |     { | ||||||
|  |         $responseTypes = array(); | ||||||
|  |  | ||||||
|  |         if ($this->config['allow_implicit']) { | ||||||
|  |             $responseTypes['token'] = $this->getAccessTokenResponseType(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($this->config['use_openid_connect']) { | ||||||
|  |             $responseTypes['id_token'] = $this->getIdTokenResponseType(); | ||||||
|  |             if ($this->config['allow_implicit']) { | ||||||
|  |                 $responseTypes['id_token token'] = $this->getIdTokenTokenResponseType(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($this->storages['authorization_code'])) { | ||||||
|  |             $config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime'))); | ||||||
|  |             if ($this->config['use_openid_connect']) { | ||||||
|  |                 if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { | ||||||
|  |                     throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); | ||||||
|  |                 } | ||||||
|  |                 $responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config); | ||||||
|  |                 $responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']); | ||||||
|  |             } else { | ||||||
|  |                 $responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (count($responseTypes) == 0) { | ||||||
|  |             throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $responseTypes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getDefaultGrantTypes() | ||||||
|  |     { | ||||||
|  |         $grantTypes = array(); | ||||||
|  |  | ||||||
|  |         if (isset($this->storages['user_credentials'])) { | ||||||
|  |             $grantTypes['password'] = new UserCredentials($this->storages['user_credentials']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($this->storages['client_credentials'])) { | ||||||
|  |             $config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => '')); | ||||||
|  |             $grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($this->storages['refresh_token'])) { | ||||||
|  |             $config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use'))); | ||||||
|  |             $grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($this->storages['authorization_code'])) { | ||||||
|  |             if ($this->config['use_openid_connect']) { | ||||||
|  |                 if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { | ||||||
|  |                     throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); | ||||||
|  |                 } | ||||||
|  |                 $grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']); | ||||||
|  |             } else { | ||||||
|  |                 $grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (count($grantTypes) == 0) { | ||||||
|  |             throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $grantTypes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getAccessTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (isset($this->responseTypes['token'])) { | ||||||
|  |             return $this->responseTypes['token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($this->config['use_jwt_access_tokens']) { | ||||||
|  |             return $this->createDefaultJwtAccessTokenResponseType(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->createDefaultAccessTokenResponseType(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getIdTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (isset($this->responseTypes['id_token'])) { | ||||||
|  |             return $this->responseTypes['id_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->createDefaultIdTokenResponseType(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getIdTokenTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (isset($this->responseTypes['id_token token'])) { | ||||||
|  |             return $this->responseTypes['id_token token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->createDefaultIdTokenTokenResponseType(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * For Resource Controller | ||||||
|  |      */ | ||||||
|  |     protected function createDefaultJwtAccessTokenStorage() | ||||||
|  |     { | ||||||
|  |         if (!isset($this->storages['public_key'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); | ||||||
|  |         } | ||||||
|  |         $tokenStorage = null; | ||||||
|  |         if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) { | ||||||
|  |             $tokenStorage = $this->storages['access_token']; | ||||||
|  |         } | ||||||
|  |         // wrap the access token storage as required. | ||||||
|  |         return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * For Authorize and Token Controllers | ||||||
|  |      */ | ||||||
|  |     protected function createDefaultJwtAccessTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (!isset($this->storages['public_key'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $tokenStorage = null; | ||||||
|  |         if (isset($this->storages['access_token'])) { | ||||||
|  |             $tokenStorage = $this->storages['access_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $refreshStorage = null; | ||||||
|  |         if (isset($this->storages['refresh_token'])) { | ||||||
|  |             $refreshStorage = $this->storages['refresh_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime'))); | ||||||
|  |  | ||||||
|  |         return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultAccessTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (!isset($this->storages['access_token'])) { | ||||||
|  |             throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $refreshStorage = null; | ||||||
|  |         if (isset($this->storages['refresh_token'])) { | ||||||
|  |             $refreshStorage = $this->storages['refresh_token']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime'))); | ||||||
|  |         $config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() :  $this->getDefaultTokenType()->getTokenType(); | ||||||
|  |  | ||||||
|  |         return new AccessToken($this->storages['access_token'], $refreshStorage, $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultIdTokenResponseType() | ||||||
|  |     { | ||||||
|  |         if (!isset($this->storages['user_claims'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect"); | ||||||
|  |         } | ||||||
|  |         if (!isset($this->storages['public_key'])) { | ||||||
|  |             throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime'))); | ||||||
|  |  | ||||||
|  |         return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function createDefaultIdTokenTokenResponseType() | ||||||
|  |     { | ||||||
|  |         return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function validateOpenIdConnect() | ||||||
|  |     { | ||||||
|  |         $authCodeGrant = $this->getGrantType('authorization_code'); | ||||||
|  |         if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) { | ||||||
|  |             throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function normalizeResponseType($name) | ||||||
|  |     { | ||||||
|  |         // for multiple-valued response types - make them alphabetical | ||||||
|  |         if (!empty($name) && false !== strpos($name, ' ')) { | ||||||
|  |             $types = explode(' ', $name); | ||||||
|  |             sort($types); | ||||||
|  |             $name = implode(' ', $types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $name; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResponse() | ||||||
|  |     { | ||||||
|  |         return $this->response; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getStorages() | ||||||
|  |     { | ||||||
|  |         return $this->storages; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getStorage($name) | ||||||
|  |     { | ||||||
|  |         return isset($this->storages[$name]) ? $this->storages[$name] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getGrantTypes() | ||||||
|  |     { | ||||||
|  |         return $this->grantTypes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getGrantType($name) | ||||||
|  |     { | ||||||
|  |         return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResponseTypes() | ||||||
|  |     { | ||||||
|  |         return $this->responseTypes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getResponseType($name) | ||||||
|  |     { | ||||||
|  |         // for multiple-valued response types - make them alphabetical | ||||||
|  |         $name = $this->normalizeResponseType($name); | ||||||
|  |  | ||||||
|  |         return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getTokenType() | ||||||
|  |     { | ||||||
|  |         return $this->tokenType; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientAssertionType() | ||||||
|  |     { | ||||||
|  |         return $this->clientAssertionType; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setConfig($name, $value) | ||||||
|  |     { | ||||||
|  |         $this->config[$name] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getConfig($name, $default = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->config[$name]) ? $this->config[$name] : $default; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get/save access tokens | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AccessTokenInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Look up the supplied oauth_token from storage. | ||||||
|  |      * | ||||||
|  |      * We need to retrieve access token data as we create and verify tokens. | ||||||
|  |      * | ||||||
|  |      * @param $oauth_token | ||||||
|  |      * oauth_token to be check with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An associative array as below, and return NULL if the supplied oauth_token | ||||||
|  |      * is invalid: | ||||||
|  |      * - expires: Stored expiration in unix timestamp. | ||||||
|  |      * - client_id: (optional) Stored client identifier. | ||||||
|  |      * - user_id: (optional) Stored user identifier. | ||||||
|  |      * - scope: (optional) Stored scope values in space-separated string. | ||||||
|  |      * - id_token: (optional) Stored id_token (if "use_openid_connect" is true). | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_7 | ||||||
|  |      */ | ||||||
|  |     public function getAccessToken($oauth_token); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store the supplied access token values to storage. | ||||||
|  |      * | ||||||
|  |      * We need to store access token data as we create and verify tokens. | ||||||
|  |      * | ||||||
|  |      * @param $oauth_token    oauth_token to be stored. | ||||||
|  |      * @param $client_id      client identifier to be stored. | ||||||
|  |      * @param $user_id        user identifier to be stored. | ||||||
|  |      * @param int    $expires expiration to be stored as a Unix timestamp. | ||||||
|  |      * @param string $scope   OPTIONAL Scopes to be stored in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Expire an access token. | ||||||
|  |      * | ||||||
|  |      * This is not explicitly required in the spec, but if defined in a draft RFC for token | ||||||
|  |      * revoking (RFC 7009) https://tools.ietf.org/html/rfc7009 | ||||||
|  |      * | ||||||
|  |      * @param $access_token | ||||||
|  |      * Access token to be expired. | ||||||
|  |      * | ||||||
|  |      * @return BOOL true if an access token was unset, false if not | ||||||
|  |      * @ingroup oauth2_section_6 | ||||||
|  |      * | ||||||
|  |      * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x | ||||||
|  |      */ | ||||||
|  |     //public function unsetAccessToken($access_token); | ||||||
|  | } | ||||||
| @@ -0,0 +1,86 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get/save authorization codes for the "Authorization Code" | ||||||
|  |  * grant type | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface AuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * The Authorization Code grant type supports a response type of "code". | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-1.4.1 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.2 | ||||||
|  |      */ | ||||||
|  |     const RESPONSE_TYPE_CODE = "code"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Fetch authorization code data (probably the most common grant type). | ||||||
|  |      * | ||||||
|  |      * Retrieve the stored data for the given authorization code. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_AUTH_CODE. | ||||||
|  |      * | ||||||
|  |      * @param $code | ||||||
|  |      * Authorization code to be check with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An associative array as below, and NULL if the code is invalid | ||||||
|  |      * @code | ||||||
|  |      * return array( | ||||||
|  |      *     "client_id"    => CLIENT_ID,      // REQUIRED Stored client identifier | ||||||
|  |      *     "user_id"      => USER_ID,        // REQUIRED Stored user identifier | ||||||
|  |      *     "expires"      => EXPIRES,        // REQUIRED Stored expiration in unix timestamp | ||||||
|  |      *     "redirect_uri" => REDIRECT_URI,   // REQUIRED Stored redirect URI | ||||||
|  |      *     "scope"        => SCOPE,          // OPTIONAL Stored scope values in space-separated string | ||||||
|  |      * ); | ||||||
|  |      * @endcode | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function getAuthorizationCode($code); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Take the provided authorization code values and store them somewhere. | ||||||
|  |      * | ||||||
|  |      * This function should be the storage counterpart to getAuthCode(). | ||||||
|  |      * | ||||||
|  |      * If storage fails for some reason, we're not currently checking for | ||||||
|  |      * any sort of success/failure, so you should bail out of the script | ||||||
|  |      * and provide a descriptive fail message. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_AUTH_CODE. | ||||||
|  |      * | ||||||
|  |      * @param string $code         Authorization code to be stored. | ||||||
|  |      * @param mixed  $client_id    Client identifier to be stored. | ||||||
|  |      * @param mixed  $user_id      User identifier to be stored. | ||||||
|  |      * @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string. | ||||||
|  |      * @param int    $expires      Expiration to be stored as a Unix timestamp. | ||||||
|  |      * @param string $scope        OPTIONAL Scopes to be stored in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * once an Authorization Code is used, it must be exipired | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.2 | ||||||
|  |      * | ||||||
|  |      *    The client MUST NOT use the authorization code | ||||||
|  |      *    more than once.  If an authorization code is used more than | ||||||
|  |      *    once, the authorization server MUST deny the request and SHOULD | ||||||
|  |      *    revoke (when possible) all tokens previously issued based on | ||||||
|  |      *    that authorization code | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     public function expireAuthorizationCode($code); | ||||||
|  | } | ||||||
							
								
								
									
										480
									
								
								library/oauth2/src/OAuth2/Storage/Cassandra.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										480
									
								
								library/oauth2/src/OAuth2/Storage/Cassandra.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,480 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use phpcassa\ColumnFamily; | ||||||
|  | use phpcassa\ColumnSlice; | ||||||
|  | use phpcassa\Connection\ConnectionPool; | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Cassandra storage for all storage types | ||||||
|  |  * | ||||||
|  |  * To use, install "thobbs/phpcassa" via composer | ||||||
|  |  * <code> | ||||||
|  |  *  composer require thobbs/phpcassa:dev-master | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * Once this is done, instantiate the | ||||||
|  |  * <code> | ||||||
|  |  *  $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160')); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * Then, register the storage client: | ||||||
|  |  * <code> | ||||||
|  |  *  $storage = new OAuth2\Storage\Cassandra($cassandra); | ||||||
|  |  *  $storage->setClientDetails($client_id, $client_secret, $redirect_uri); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage | ||||||
|  |  */ | ||||||
|  | class Cassandra implements AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     ScopeInterface, | ||||||
|  |     PublicKeyInterface, | ||||||
|  |     UserClaimsInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private $cache; | ||||||
|  |  | ||||||
|  |     /* The cassandra client */ | ||||||
|  |     protected $cassandra; | ||||||
|  |  | ||||||
|  |     /* Configuration array */ | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cassandra Storage! uses phpCassa | ||||||
|  |      * | ||||||
|  |      * @param \phpcassa\ConnectionPool $cassandra | ||||||
|  |      * @param array                    $config | ||||||
|  |      */ | ||||||
|  |     public function __construct($connection = array(), array $config = array()) | ||||||
|  |     { | ||||||
|  |         if ($connection instanceof ConnectionPool) { | ||||||
|  |             $this->cassandra = $connection; | ||||||
|  |         } else { | ||||||
|  |             if (!is_array($connection)) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array'); | ||||||
|  |             } | ||||||
|  |             $connection = array_merge(array( | ||||||
|  |                 'keyspace' => 'oauth2', | ||||||
|  |                 'servers'  => null, | ||||||
|  |             ), $connection); | ||||||
|  |  | ||||||
|  |             $this->cassandra = new ConnectionPool($connection['keyspace'], $connection['servers']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             // cassandra config | ||||||
|  |             'column_family' => 'auth', | ||||||
|  |  | ||||||
|  |             // key names | ||||||
|  |             'client_key' => 'oauth_clients:', | ||||||
|  |             'access_token_key' => 'oauth_access_tokens:', | ||||||
|  |             'refresh_token_key' => 'oauth_refresh_tokens:', | ||||||
|  |             'code_key' => 'oauth_authorization_codes:', | ||||||
|  |             'user_key' => 'oauth_users:', | ||||||
|  |             'jwt_key' => 'oauth_jwt:', | ||||||
|  |             'scope_key' => 'oauth_scopes:', | ||||||
|  |             'public_key_key'  => 'oauth_public_keys:', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getValue($key) | ||||||
|  |     { | ||||||
|  |         if (isset($this->cache[$key])) { | ||||||
|  |             return $this->cache[$key]; | ||||||
|  |         } | ||||||
|  |         $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             $value = $cf->get($key, new ColumnSlice("", "")); | ||||||
|  |             $value = array_shift($value); | ||||||
|  |         } catch (\cassandra\NotFoundException $e) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return json_decode($value, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function setValue($key, $value, $expire = 0) | ||||||
|  |     { | ||||||
|  |         $this->cache[$key] = $value; | ||||||
|  |  | ||||||
|  |         $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); | ||||||
|  |  | ||||||
|  |         $str = json_encode($value); | ||||||
|  |         if ($expire > 0) { | ||||||
|  |             try { | ||||||
|  |                 $seconds = $expire - time(); | ||||||
|  |                 // __data key set as C* requires a field, note: max TTL can only be 630720000 seconds | ||||||
|  |                 $cf->insert($key, array('__data' => $str), null, $seconds); | ||||||
|  |             } catch (\Exception $e) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             try { | ||||||
|  |                 // __data key set as C* requires a field | ||||||
|  |                 $cf->insert($key, array('__data' => $str)); | ||||||
|  |             } catch (\Exception $e) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function expireValue($key) | ||||||
|  |     { | ||||||
|  |         unset($this->cache[$key]); | ||||||
|  |  | ||||||
|  |         $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); | ||||||
|  |  | ||||||
|  |         if ($cf->get_count($key) > 0) { | ||||||
|  |             try { | ||||||
|  |                 // __data key set as C* requires a field | ||||||
|  |                 $cf->remove($key, array('__data')); | ||||||
|  |             } catch (\Exception $e) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['code_key'] . $code); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['code_key'] . $authorization_code, | ||||||
|  |             compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $key = $this->config['code_key'] . $code; | ||||||
|  |         unset($this->cache[$key]); | ||||||
|  |  | ||||||
|  |         return $this->expireValue($key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             return $this->checkPassword($user, $password); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // plaintext passwords are bad!  Override this for your application | ||||||
|  |     protected function checkPassword($user, $password) | ||||||
|  |     { | ||||||
|  |         return $user['password'] == $this->hashPassword($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // use a secure hashing algorithm when storing passwords. Override this for your application | ||||||
|  |     protected function hashPassword($password) | ||||||
|  |     { | ||||||
|  |         return sha1($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         return $this->getUser($username); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the default behavior is to use "username" as the user_id | ||||||
|  |         return array_merge(array( | ||||||
|  |             'user_id' => $username, | ||||||
|  |         ), $userInfo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $first_name = null, $last_name = null) | ||||||
|  |     { | ||||||
|  |         $password = $this->hashPassword($password); | ||||||
|  |  | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['user_key'] . $username, | ||||||
|  |             compact('username', 'password', 'first_name', 'last_name') | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         if (!$client = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return isset($client['client_secret']) | ||||||
|  |             && $client['client_secret'] == $client_secret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$client = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($client['client_secret']);; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['client_key'] . $client_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['client_key'] . $client_id, | ||||||
|  |             compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, (array) $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['refresh_token_key'] . $refresh_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['refresh_token_key'] . $refresh_token, | ||||||
|  |             compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         return $this->expireValue($this->config['refresh_token_key'] . $refresh_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['access_token_key'].$access_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['access_token_key'].$access_token, | ||||||
|  |             compact('access_token', 'client_id', 'user_id', 'expires', 'scope'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         return $this->expireValue($this->config['access_token_key'] . $access_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ScopeInterface */ | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         $scope = explode(' ', $scope); | ||||||
|  |  | ||||||
|  |         $result = $this->getValue($this->config['scope_key'].'supported:global'); | ||||||
|  |  | ||||||
|  |         $supportedScope = explode(' ', (string) $result); | ||||||
|  |  | ||||||
|  |         return (count(array_diff($scope, $supportedScope)) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) { | ||||||
|  |             $result = $this->getValue($this->config['scope_key'].'default:global'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setScope($scope, $client_id = null, $type = 'supported') | ||||||
|  |     { | ||||||
|  |         if (!in_array($type, array('default', 'supported'))) { | ||||||
|  |             throw new \InvalidArgumentException('"$type" must be one of "default", "supported"'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_null($client_id)) { | ||||||
|  |             $key = $this->config['scope_key'].$type.':global'; | ||||||
|  |         } else { | ||||||
|  |             $key = $this->config['scope_key'].$type.':'.$client_id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->setValue($key, $scope); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*JWTBearerInterface */ | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($jwt['subject']) && $jwt['subject'] == $subject ) { | ||||||
|  |             return $jwt['key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientKey($client_id, $key, $subject = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue($this->config['jwt_key'] . $client_id, array( | ||||||
|  |             'key' => $key, | ||||||
|  |             'subject' => $subject | ||||||
|  |         )); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*ScopeInterface */ | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs cassandra implementation. | ||||||
|  |         throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs cassandra implementation. | ||||||
|  |         throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* PublicKeyInterface */ | ||||||
|  |     public function getPublicKey($client_id = '') | ||||||
|  |     { | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key'] . $client_id); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['public_key']; | ||||||
|  |         } | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key']); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['public_key']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPrivateKey($client_id = '') | ||||||
|  |     { | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key'] . $client_id); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['private_key']; | ||||||
|  |         } | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key']); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['private_key']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getEncryptionAlgorithm($client_id = null) | ||||||
|  |     { | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key'] . $client_id); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['encryption_algorithm']; | ||||||
|  |         } | ||||||
|  |         $public_key = $this->getValue($this->config['public_key_key']); | ||||||
|  |         if (is_array($public_key)) { | ||||||
|  |             return $public_key['encryption_algorithm']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 'RS256'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserClaimsInterface */ | ||||||
|  |     public function getUserClaims($user_id, $claims) | ||||||
|  |     { | ||||||
|  |         $userDetails = $this->getUserDetails($user_id); | ||||||
|  |         if (!is_array($userDetails)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $claims = explode(' ', trim($claims)); | ||||||
|  |         $userClaims = array(); | ||||||
|  |  | ||||||
|  |         // for each requested claim, if the user has the claim, set it in the response | ||||||
|  |         $validClaims = explode(' ', self::VALID_CLAIMS); | ||||||
|  |         foreach ($validClaims as $validClaim) { | ||||||
|  |             if (in_array($validClaim, $claims)) { | ||||||
|  |                 if ($validClaim == 'address') { | ||||||
|  |                     // address is an object with subfields | ||||||
|  |                     $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); | ||||||
|  |                 } else { | ||||||
|  |                     $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getUserClaim($claim, $userDetails) | ||||||
|  |     { | ||||||
|  |         $userClaims = array(); | ||||||
|  |         $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); | ||||||
|  |         $claimValues = explode(' ', $claimValuesString); | ||||||
|  |  | ||||||
|  |         foreach ($claimValues as $value) { | ||||||
|  |             if ($value == 'email_verified') { | ||||||
|  |                 $userClaims[$value] = $userDetails[$value]=='true' ? true : false; | ||||||
|  |             } else { | ||||||
|  |                 $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,49 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify how the OAuth2 Server | ||||||
|  |  * should verify client credentials | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface ClientCredentialsInterface extends ClientInterface | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Make sure that the client credentials is valid. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be check with. | ||||||
|  |      * @param $client_secret | ||||||
|  |      * (optional) If a secret is required, check that they've given the right one. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the client credentials are valid, and MUST return FALSE if it isn't. | ||||||
|  |      * @endcode | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-3.1 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_3 | ||||||
|  |      */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine if the client is a "public" client, and therefore | ||||||
|  |      * does not require passing credentials for certain grant types | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be check with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the client is public, and FALSE if it isn't. | ||||||
|  |      * @endcode | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-2.3 | ||||||
|  |      * @see https://github.com/bshaffer/oauth2-server-php/issues/257 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_2 | ||||||
|  |      */ | ||||||
|  |     public function isPublicClient($client_id); | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								library/oauth2/src/OAuth2/Storage/ClientInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								library/oauth2/src/OAuth2/Storage/ClientInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should retrieve client information | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface ClientInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Get client details corresponding client_id. | ||||||
|  |      * | ||||||
|  |      * OAuth says we should store request URIs for each registered client. | ||||||
|  |      * Implement this function to grab the stored URI for a given client id. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be check with. | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      *               Client details. The only mandatory key in the array is "redirect_uri". | ||||||
|  |      *               This function MUST return FALSE if the given client does not exist or is | ||||||
|  |      *               invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris. | ||||||
|  |      *               <code> | ||||||
|  |      *               return array( | ||||||
|  |      *               "redirect_uri" => REDIRECT_URI,      // REQUIRED redirect_uri registered for the client | ||||||
|  |      *               "client_id"    => CLIENT_ID,         // OPTIONAL the client id | ||||||
|  |      *               "grant_types"  => GRANT_TYPES,       // OPTIONAL an array of restricted grant types | ||||||
|  |      *               "user_id"      => USER_ID,           // OPTIONAL the user identifier associated with this client | ||||||
|  |      *               "scope"        => SCOPE,             // OPTIONAL the scopes allowed for this client | ||||||
|  |      *               ); | ||||||
|  |      *               </code> | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function getClientDetails($client_id); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the scope associated with this client | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * STRING the space-delineated scope list for the specified client_id | ||||||
|  |      */ | ||||||
|  |     public function getClientScope($client_id); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check restricted grant types of corresponding client identifier. | ||||||
|  |      * | ||||||
|  |      * If you want to restrict clients to certain grant types, override this | ||||||
|  |      * function. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be check with. | ||||||
|  |      * @param $grant_type | ||||||
|  |      * Grant type to be check with | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the grant type is supported by this client identifier, and | ||||||
|  |      * FALSE if it isn't. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type); | ||||||
|  | } | ||||||
							
								
								
									
										331
									
								
								library/oauth2/src/OAuth2/Storage/CouchbaseDB.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										331
									
								
								library/oauth2/src/OAuth2/Storage/CouchbaseDB.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,331 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple Couchbase storage for all storage types | ||||||
|  |  * | ||||||
|  |  * This class should be extended or overridden as required | ||||||
|  |  * | ||||||
|  |  * NOTE: Passwords are stored in plaintext, which is never | ||||||
|  |  * a good idea.  Be sure to override this for your application | ||||||
|  |  * | ||||||
|  |  * @author Tom Park <tom@raucter.com> | ||||||
|  |  */ | ||||||
|  | class CouchbaseDB implements AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     protected $db; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     public function __construct($connection, $config = array()) | ||||||
|  |     { | ||||||
|  |         if ($connection instanceof \Couchbase) { | ||||||
|  |             $this->db = $connection; | ||||||
|  |         } else { | ||||||
|  |             if (!is_array($connection) || !is_array($connection['servers'])) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array'); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'client_table' => 'oauth_clients', | ||||||
|  |             'access_token_table' => 'oauth_access_tokens', | ||||||
|  |             'refresh_token_table' => 'oauth_refresh_tokens', | ||||||
|  |             'code_table' => 'oauth_authorization_codes', | ||||||
|  |             'user_table' => 'oauth_users', | ||||||
|  |             'jwt_table' => 'oauth_jwt', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Helper function to access couchbase item by type: | ||||||
|  |     protected function getObjectByType($name,$id) | ||||||
|  |     { | ||||||
|  |         return json_decode($this->db->get($this->config[$name].'-'.$id),true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Helper function to set couchbase item by type: | ||||||
|  |     protected function setObjectByType($name,$id,$array) | ||||||
|  |     { | ||||||
|  |         $array['type'] = $name; | ||||||
|  |  | ||||||
|  |         return $this->db->set($this->config[$name].'-'.$id,json_encode($array)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Helper function to delete couchbase item by type, wait for persist to at least 1 node | ||||||
|  |     protected function deleteObjectByType($name,$id) | ||||||
|  |     { | ||||||
|  |         $this->db->delete($this->config[$name].'-'.$id,"",1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         if ($result = $this->getObjectByType('client_table',$client_id)) { | ||||||
|  |             return $result['client_secret'] == $client_secret; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$result = $this->getObjectByType('client_table',$client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($result['client_secret']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         $result = $this->getObjectByType('client_table',$client_id); | ||||||
|  |  | ||||||
|  |         return is_null($result) ? false : $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         if ($this->getClientDetails($client_id)) { | ||||||
|  |  | ||||||
|  |             $this->setObjectByType('client_table',$client_id, array( | ||||||
|  |                 'client_id'     => $client_id, | ||||||
|  |                 'client_secret' => $client_secret, | ||||||
|  |                 'redirect_uri'  => $redirect_uri, | ||||||
|  |                 'grant_types'   => $grant_types, | ||||||
|  |                 'scope'         => $scope, | ||||||
|  |                 'user_id'       => $user_id, | ||||||
|  |             )); | ||||||
|  |         } else { | ||||||
|  |             $this->setObjectByType('client_table',$client_id, array( | ||||||
|  |                 'client_id'     => $client_id, | ||||||
|  |                 'client_secret' => $client_secret, | ||||||
|  |                 'redirect_uri'  => $redirect_uri, | ||||||
|  |                 'grant_types'   => $grant_types, | ||||||
|  |                 'scope'         => $scope, | ||||||
|  |                 'user_id'       => $user_id, | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $token = $this->getObjectByType('access_token_table',$access_token); | ||||||
|  |  | ||||||
|  |         return is_null($token) ? false : $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAccessToken($access_token)) { | ||||||
|  |             $this->setObjectByType('access_token_table',$access_token, array( | ||||||
|  |                 'access_token' => $access_token, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'scope' => $scope | ||||||
|  |             )); | ||||||
|  |         } else { | ||||||
|  |             $this->setObjectByType('access_token_table',$access_token,  array( | ||||||
|  |                 'access_token' => $access_token, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'scope' => $scope | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $code = $this->getObjectByType('code_table',$code); | ||||||
|  |  | ||||||
|  |         return is_null($code) ? false : $code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAuthorizationCode($code)) { | ||||||
|  |             $this->setObjectByType('code_table',$code, array( | ||||||
|  |                 'authorization_code' => $code, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'redirect_uri' => $redirect_uri, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'scope' => $scope, | ||||||
|  |                 'id_token' => $id_token, | ||||||
|  |             )); | ||||||
|  |         } else { | ||||||
|  |             $this->setObjectByType('code_table',$code,array( | ||||||
|  |                 'authorization_code' => $code, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'redirect_uri' => $redirect_uri, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'scope' => $scope, | ||||||
|  |                 'id_token' => $id_token, | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $this->deleteObjectByType('code_table',$code); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             return $this->checkPassword($user, $password); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             $user['user_id'] = $user['username']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $user; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $token = $this->getObjectByType('refresh_token_table',$refresh_token); | ||||||
|  |  | ||||||
|  |         return is_null($token) ? false : $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         $this->setObjectByType('refresh_token_table',$refresh_token, array( | ||||||
|  |             'refresh_token' => $refresh_token, | ||||||
|  |             'client_id' => $client_id, | ||||||
|  |             'user_id' => $user_id, | ||||||
|  |             'expires' => $expires, | ||||||
|  |             'scope' => $scope | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $this->deleteObjectByType('refresh_token_table',$refresh_token); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // plaintext passwords are bad!  Override this for your application | ||||||
|  |     protected function checkPassword($user, $password) | ||||||
|  |     { | ||||||
|  |         return $user['password'] == $password; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         $result = $this->getObjectByType('user_table',$username); | ||||||
|  |  | ||||||
|  |         return is_null($result) ? false : $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $firstName = null, $lastName = null) | ||||||
|  |     { | ||||||
|  |         if ($this->getUser($username)) { | ||||||
|  |             $this->setObjectByType('user_table',$username, array( | ||||||
|  |                 'username' => $username, | ||||||
|  |                 'password' => $password, | ||||||
|  |                 'first_name' => $firstName, | ||||||
|  |                 'last_name' => $lastName | ||||||
|  |             )); | ||||||
|  |  | ||||||
|  |         } else { | ||||||
|  |             $this->setObjectByType('user_table',$username, array( | ||||||
|  |                 'username' => $username, | ||||||
|  |                 'password' => $password, | ||||||
|  |                 'first_name' => $firstName, | ||||||
|  |                 'last_name' => $lastName | ||||||
|  |             )); | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         if (!$jwt = $this->getObjectByType('jwt_table',$client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($jwt['subject']) && $jwt['subject'] == $subject) { | ||||||
|  |             return $jwt['key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs couchbase implementation. | ||||||
|  |         throw new \Exception('getJti() for the Couchbase driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs couchbase implementation. | ||||||
|  |         throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										540
									
								
								library/oauth2/src/OAuth2/Storage/DynamoDB.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								library/oauth2/src/OAuth2/Storage/DynamoDB.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use Aws\DynamoDb\DynamoDbClient; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  | /** | ||||||
|  |  * DynamoDB storage for all storage types | ||||||
|  |  * | ||||||
|  |  * To use, install "aws/aws-sdk-php" via composer | ||||||
|  |  * <code> | ||||||
|  |  *  composer require aws/aws-sdk-php:dev-master | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * Once this is done, instantiate the DynamoDB client | ||||||
|  |  * <code> | ||||||
|  |  *  $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION")); | ||||||
|  |  * </code> | ||||||
|  |  * | ||||||
|  |  * Table : | ||||||
|  |  *  - oauth_access_tokens (primary hash key : access_token) | ||||||
|  |  *  - oauth_authorization_codes (primary hash key : authorization_code) | ||||||
|  |  *  - oauth_clients (primary hash key : client_id) | ||||||
|  |  *  - oauth_jwt (primary hash key : client_id, primary range key : subject) | ||||||
|  |  *  - oauth_public_keys (primary hash key : client_id) | ||||||
|  |  *  - oauth_refresh_tokens (primary hash key : refresh_token) | ||||||
|  |  *  - oauth_scopes (primary hash key : scope, secondary index : is_default-index hash key is_default) | ||||||
|  |  *  - oauth_users (primary hash key : username) | ||||||
|  |  * | ||||||
|  |  * @author Frederic AUGUSTE <frederic.auguste at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class DynamoDB implements | ||||||
|  |     AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     ScopeInterface, | ||||||
|  |     PublicKeyInterface, | ||||||
|  |     UserClaimsInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     protected $client; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     public function __construct($connection, $config = array()) | ||||||
|  |     { | ||||||
|  |         if (!($connection instanceof DynamoDbClient)) { | ||||||
|  |             if (!is_array($connection)) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region'); | ||||||
|  |             } | ||||||
|  |             if (!array_key_exists("key",$connection) || !array_key_exists("secret",$connection) || !array_key_exists("region",$connection) ) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region'); | ||||||
|  |             } | ||||||
|  |             $this->client = DynamoDbClient::factory(array( | ||||||
|  |                 'key' => $connection["key"], | ||||||
|  |                 'secret' => $connection["secret"], | ||||||
|  |                 'region' =>$connection["region"] | ||||||
|  |             )); | ||||||
|  |         } else { | ||||||
|  |             $this->client = $connection; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'client_table' => 'oauth_clients', | ||||||
|  |             'access_token_table' => 'oauth_access_tokens', | ||||||
|  |             'refresh_token_table' => 'oauth_refresh_tokens', | ||||||
|  |             'code_table' => 'oauth_authorization_codes', | ||||||
|  |             'user_table' => 'oauth_users', | ||||||
|  |             'jwt_table'  => 'oauth_jwt', | ||||||
|  |             'scope_table'  => 'oauth_scopes', | ||||||
|  |             'public_key_table'  => 'oauth_public_keys', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['client_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return  $result->count()==1 && $result["Item"]["client_secret"]["S"] == $client_secret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['client_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($result["Item"]["client_secret"]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['client_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $result = $this->dynamo2array($result); | ||||||
|  |         foreach (array('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') as $key => $val) { | ||||||
|  |             if (!array_key_exists ($val, $result)) { | ||||||
|  |                 $result[$val] = null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $clientData = compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'); | ||||||
|  |         $clientData = array_filter($clientData, 'self::isNotEmpty'); | ||||||
|  |  | ||||||
|  |         $result = $this->client->putItem(array( | ||||||
|  |             'TableName' =>  $this->config['client_table'], | ||||||
|  |             'Item' => $this->client->formatAttributes($clientData) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, (array) $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['access_token_table'], | ||||||
|  |             "Key" => array('access_token'   => array('S' => $access_token)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |         if (array_key_exists ('expires', $token)) { | ||||||
|  |             $token['expires'] = strtotime($token['expires']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         $clientData = compact('access_token', 'client_id', 'user_id', 'expires', 'scope'); | ||||||
|  |         $clientData = array_filter($clientData, 'self::isNotEmpty'); | ||||||
|  |  | ||||||
|  |         $result = $this->client->putItem(array( | ||||||
|  |             'TableName' =>  $this->config['access_token_table'], | ||||||
|  |             'Item' => $this->client->formatAttributes($clientData) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->deleteItem(array( | ||||||
|  |             'TableName' =>  $this->config['access_token_table'], | ||||||
|  |             'Key' => $this->client->formatAttributes(array("access_token" => $access_token)), | ||||||
|  |             'ReturnValues' => 'ALL_OLD', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return null !== $result->get('Attributes'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['code_table'], | ||||||
|  |             "Key" => array('authorization_code'   => array('S' => $code)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |         if (!array_key_exists("id_token", $token )) { | ||||||
|  |             $token['id_token'] = null; | ||||||
|  |         } | ||||||
|  |         $token['expires'] = strtotime($token['expires']); | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         $clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'id_token', 'scope'); | ||||||
|  |         $clientData = array_filter($clientData, 'self::isNotEmpty'); | ||||||
|  |  | ||||||
|  |         $result = $this->client->putItem(array( | ||||||
|  |             'TableName' =>  $this->config['code_table'], | ||||||
|  |             'Item' => $this->client->formatAttributes($clientData) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         $result = $this->client->deleteItem(array( | ||||||
|  |             'TableName' =>  $this->config['code_table'], | ||||||
|  |             'Key' => $this->client->formatAttributes(array("authorization_code" => $code)) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             return $this->checkPassword($user, $password); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         return $this->getUser($username); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserClaimsInterface */ | ||||||
|  |     public function getUserClaims($user_id, $claims) | ||||||
|  |     { | ||||||
|  |         if (!$userDetails = $this->getUserDetails($user_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $claims = explode(' ', trim($claims)); | ||||||
|  |         $userClaims = array(); | ||||||
|  |  | ||||||
|  |         // for each requested claim, if the user has the claim, set it in the response | ||||||
|  |         $validClaims = explode(' ', self::VALID_CLAIMS); | ||||||
|  |         foreach ($validClaims as $validClaim) { | ||||||
|  |             if (in_array($validClaim, $claims)) { | ||||||
|  |                 if ($validClaim == 'address') { | ||||||
|  |                     // address is an object with subfields | ||||||
|  |                     $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); | ||||||
|  |                 } else { | ||||||
|  |                     $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getUserClaim($claim, $userDetails) | ||||||
|  |     { | ||||||
|  |         $userClaims = array(); | ||||||
|  |         $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); | ||||||
|  |         $claimValues = explode(' ', $claimValuesString); | ||||||
|  |  | ||||||
|  |         foreach ($claimValues as $value) { | ||||||
|  |             if ($value == 'email_verified') { | ||||||
|  |                 $userClaims[$value] = $userDetails[$value]=='true' ? true : false; | ||||||
|  |             } else { | ||||||
|  |                 $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['refresh_token_table'], | ||||||
|  |             "Key" => array('refresh_token'   => array('S' => $refresh_token)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |         $token['expires'] = strtotime($token['expires']); | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         $clientData = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'); | ||||||
|  |         $clientData = array_filter($clientData, 'self::isNotEmpty'); | ||||||
|  |  | ||||||
|  |         $result = $this->client->putItem(array( | ||||||
|  |             'TableName' =>  $this->config['refresh_token_table'], | ||||||
|  |             'Item' => $this->client->formatAttributes($clientData) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->deleteItem(array( | ||||||
|  |             'TableName' =>  $this->config['refresh_token_table'], | ||||||
|  |             'Key' => $this->client->formatAttributes(array("refresh_token" => $refresh_token)) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // plaintext passwords are bad!  Override this for your application | ||||||
|  |     protected function checkPassword($user, $password) | ||||||
|  |     { | ||||||
|  |         return $user['password'] == $this->hashPassword($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // use a secure hashing algorithm when storing passwords. Override this for your application | ||||||
|  |     protected function hashPassword($password) | ||||||
|  |     { | ||||||
|  |         return sha1($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['user_table'], | ||||||
|  |             "Key" => array('username'   => array('S' => $username)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |         $token['user_id'] = $username; | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $first_name = null, $last_name = null) | ||||||
|  |     { | ||||||
|  |         // do not store in plaintext | ||||||
|  |         $password = $this->hashPassword($password); | ||||||
|  |  | ||||||
|  |         $clientData = compact('username', 'password', 'first_name', 'last_name'); | ||||||
|  |         $clientData = array_filter($clientData, 'self::isNotEmpty'); | ||||||
|  |  | ||||||
|  |         $result = $this->client->putItem(array( | ||||||
|  |             'TableName' =>  $this->config['user_table'], | ||||||
|  |             'Item' => $this->client->formatAttributes($clientData) | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ScopeInterface */ | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         $scope = explode(' ', $scope); | ||||||
|  |         $scope_query = array(); | ||||||
|  |         $count = 0; | ||||||
|  |         foreach ($scope as $key => $val) { | ||||||
|  |             $result = $this->client->query(array( | ||||||
|  |                 'TableName'     => $this->config['scope_table'], | ||||||
|  |                 'Select'        => 'COUNT', | ||||||
|  |                 'KeyConditions' => array( | ||||||
|  |                     'scope' => array( | ||||||
|  |                         'AttributeValueList' => array(array('S' => $val)), | ||||||
|  |                         'ComparisonOperator' => 'EQ' | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             )); | ||||||
|  |             $count += $result['Count']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $count == count($scope); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         $result = $this->client->query(array( | ||||||
|  |             'TableName' => $this->config['scope_table'], | ||||||
|  |             'IndexName' => 'is_default-index', | ||||||
|  |             'Select' => 'ALL_ATTRIBUTES', | ||||||
|  |             'KeyConditions' => array( | ||||||
|  |                 'is_default' => array( | ||||||
|  |                     'AttributeValueList' => array(array('S' => 'true')), | ||||||
|  |                     'ComparisonOperator' => 'EQ', | ||||||
|  |                 ), | ||||||
|  |             ) | ||||||
|  |         )); | ||||||
|  |         $defaultScope = array(); | ||||||
|  |         if ($result->count() > 0) { | ||||||
|  |             $array = $result->toArray(); | ||||||
|  |             foreach ($array["Items"] as $item) { | ||||||
|  |                 $defaultScope[]  = $item['scope']['S']; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return empty($defaultScope) ? null : implode(' ', $defaultScope); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* JWTBearerInterface */ | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['jwt_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id), 'subject' => array('S' => $subject)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |  | ||||||
|  |         return $token['public_key']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO not use. | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO not use. | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* PublicKeyInterface */ | ||||||
|  |     public function getPublicKey($client_id = '0') | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['public_key_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |  | ||||||
|  |         return $token['public_key']; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPrivateKey($client_id = '0') | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['public_key_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return false ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |  | ||||||
|  |         return $token['private_key']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getEncryptionAlgorithm($client_id = null) | ||||||
|  |     { | ||||||
|  |         $result = $this->client->getItem(array( | ||||||
|  |             "TableName"=> $this->config['public_key_table'], | ||||||
|  |             "Key" => array('client_id'   => array('S' => $client_id)) | ||||||
|  |         )); | ||||||
|  |         if ($result->count()==0) { | ||||||
|  |             return 'RS256' ; | ||||||
|  |         } | ||||||
|  |         $token = $this->dynamo2array($result); | ||||||
|  |  | ||||||
|  |         return $token['encryption_algorithm']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Transform dynamodb resultset to an array. | ||||||
|  |      * @param $dynamodbResult | ||||||
|  |      * @return $array | ||||||
|  |      */ | ||||||
|  |     private function dynamo2array($dynamodbResult) | ||||||
|  |     { | ||||||
|  |         $result = array(); | ||||||
|  |         foreach ($dynamodbResult["Item"] as $key => $val) { | ||||||
|  |             $result[$key] = $val["S"]; | ||||||
|  |             $result[] = $val["S"]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static function isNotEmpty($value) | ||||||
|  |     { | ||||||
|  |         return null !== $value && '' !== $value; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								library/oauth2/src/OAuth2/Storage/JwtAccessToken.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								library/oauth2/src/OAuth2/Storage/JwtAccessToken.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\Encryption\EncryptionInterface; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class JwtAccessToken implements JwtAccessTokenInterface | ||||||
|  | { | ||||||
|  |     protected $publicKeyStorage; | ||||||
|  |     protected $tokenStorage; | ||||||
|  |     protected $encryptionUtil; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param OAuth2\Encryption\PublicKeyInterface  $publicKeyStorage the public key encryption to use | ||||||
|  |      * @param OAuth2\Storage\AccessTokenInterface   $tokenStorage     OPTIONAL persist the access token to another storage. This is useful if | ||||||
|  |      *                                                                you want to retain access token grant information somewhere, but | ||||||
|  |      *                                                                is not necessary when using this grant type. | ||||||
|  |      * @param OAuth2\Encryption\EncryptionInterface $encryptionUtil   OPTIONAL class to use for "encode" and "decode" functions. | ||||||
|  |      */ | ||||||
|  |     public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null) | ||||||
|  |     { | ||||||
|  |         $this->publicKeyStorage = $publicKeyStorage; | ||||||
|  |         $this->tokenStorage = $tokenStorage; | ||||||
|  |         if (is_null($encryptionUtil)) { | ||||||
|  |             $encryptionUtil = new Jwt; | ||||||
|  |         } | ||||||
|  |         $this->encryptionUtil = $encryptionUtil; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAccessToken($oauth_token) | ||||||
|  |     { | ||||||
|  |         // just decode the token, don't verify | ||||||
|  |         if (!$tokenData = $this->encryptionUtil->decode($oauth_token, null, false)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $client_id  = isset($tokenData['aud']) ? $tokenData['aud'] : null; | ||||||
|  |         $public_key = $this->publicKeyStorage->getPublicKey($client_id); | ||||||
|  |         $algorithm  = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); | ||||||
|  |  | ||||||
|  |         // now that we have the client_id, verify the token | ||||||
|  |         if (false === $this->encryptionUtil->decode($oauth_token, $public_key, array($algorithm))) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // normalize the JWT claims to the format expected by other components in this library | ||||||
|  |         return $this->convertJwtToOAuth2($tokenData); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         if ($this->tokenStorage) { | ||||||
|  |             return $this->tokenStorage->setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         if ($this->tokenStorage) { | ||||||
|  |             return $this->tokenStorage->unsetAccessToken($access_token); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // converts a JWT access token into an OAuth2-friendly format | ||||||
|  |     protected function convertJwtToOAuth2($tokenData) | ||||||
|  |     { | ||||||
|  |         $keyMapping = array( | ||||||
|  |             'aud' => 'client_id', | ||||||
|  |             'exp' => 'expires', | ||||||
|  |             'sub' => 'user_id' | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         foreach ($keyMapping as $jwtKey => $oauth2Key) { | ||||||
|  |             if (isset($tokenData[$jwtKey])) { | ||||||
|  |                 $tokenData[$oauth2Key] = $tokenData[$jwtKey]; | ||||||
|  |                 unset($tokenData[$jwtKey]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $tokenData; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * No specific methods, but allows the library to check "instanceof" | ||||||
|  |  * against interface rather than class | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface JwtAccessTokenInterface extends AccessTokenInterface | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get the JWT key for clients | ||||||
|  |  * | ||||||
|  |  * @TODO consider extending ClientInterface, as this will almost always | ||||||
|  |  * be the same storage as retrieving clientData | ||||||
|  |  * | ||||||
|  |  * @author F21 | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface JwtBearerInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Get the public key associated with a client_id | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be checked with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * STRING Return the public key for the client_id if it exists, and MUST return FALSE if it doesn't. | ||||||
|  |      */ | ||||||
|  |     public function getClientKey($client_id, $subject); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get a jti (JSON token identifier) by matching against the client_id, subject, audience and expiration. | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to match. | ||||||
|  |      * | ||||||
|  |      * @param $subject | ||||||
|  |      * The subject to match. | ||||||
|  |      * | ||||||
|  |      * @param $audience | ||||||
|  |      * The audience to match. | ||||||
|  |      * | ||||||
|  |      * @param $expiration | ||||||
|  |      * The expiration of the jti. | ||||||
|  |      * | ||||||
|  |      * @param $jti | ||||||
|  |      * The jti to match. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An associative array as below, and return NULL if the jti does not exist. | ||||||
|  |      * - issuer: Stored client identifier. | ||||||
|  |      * - subject: Stored subject. | ||||||
|  |      * - audience: Stored audience. | ||||||
|  |      * - expires: Stored expiration in unix timestamp. | ||||||
|  |      * - jti: The stored jti. | ||||||
|  |      */ | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expiration, $jti); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a used jti so that we can check against it to prevent replay attacks. | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to insert. | ||||||
|  |      * | ||||||
|  |      * @param $subject | ||||||
|  |      * The subject to insert. | ||||||
|  |      * | ||||||
|  |      * @param $audience | ||||||
|  |      * The audience to insert. | ||||||
|  |      * | ||||||
|  |      * @param $expiration | ||||||
|  |      * The expiration of the jti. | ||||||
|  |      * | ||||||
|  |      * @param $jti | ||||||
|  |      * The jti to insert. | ||||||
|  |      */ | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expiration, $jti); | ||||||
|  | } | ||||||
							
								
								
									
										381
									
								
								library/oauth2/src/OAuth2/Storage/Memory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								library/oauth2/src/OAuth2/Storage/Memory.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,381 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple in-memory storage for all storage types | ||||||
|  |  * | ||||||
|  |  * NOTE: This class should never be used in production, and is | ||||||
|  |  * a stub class for example use only | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class Memory implements AuthorizationCodeInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     UserClaimsInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     ScopeInterface, | ||||||
|  |     PublicKeyInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     public $authorizationCodes; | ||||||
|  |     public $userCredentials; | ||||||
|  |     public $clientCredentials; | ||||||
|  |     public $refreshTokens; | ||||||
|  |     public $accessTokens; | ||||||
|  |     public $jwt; | ||||||
|  |     public $jti; | ||||||
|  |     public $supportedScopes; | ||||||
|  |     public $defaultScope; | ||||||
|  |     public $keys; | ||||||
|  |  | ||||||
|  |     public function __construct($params = array()) | ||||||
|  |     { | ||||||
|  |         $params = array_merge(array( | ||||||
|  |             'authorization_codes' => array(), | ||||||
|  |             'user_credentials' => array(), | ||||||
|  |             'client_credentials' => array(), | ||||||
|  |             'refresh_tokens' => array(), | ||||||
|  |             'access_tokens' => array(), | ||||||
|  |             'jwt' => array(), | ||||||
|  |             'jti' => array(), | ||||||
|  |             'default_scope' => null, | ||||||
|  |             'supported_scopes' => array(), | ||||||
|  |             'keys' => array(), | ||||||
|  |         ), $params); | ||||||
|  |  | ||||||
|  |         $this->authorizationCodes = $params['authorization_codes']; | ||||||
|  |         $this->userCredentials = $params['user_credentials']; | ||||||
|  |         $this->clientCredentials = $params['client_credentials']; | ||||||
|  |         $this->refreshTokens = $params['refresh_tokens']; | ||||||
|  |         $this->accessTokens = $params['access_tokens']; | ||||||
|  |         $this->jwt = $params['jwt']; | ||||||
|  |         $this->jti = $params['jti']; | ||||||
|  |         $this->supportedScopes = $params['supported_scopes']; | ||||||
|  |         $this->defaultScope = $params['default_scope']; | ||||||
|  |         $this->keys = $params['keys']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         if (!isset($this->authorizationCodes[$code])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array_merge(array( | ||||||
|  |             'authorization_code' => $code, | ||||||
|  |         ), $this->authorizationCodes[$code]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         $this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCodes($authorization_codes) | ||||||
|  |     { | ||||||
|  |         $this->authorizationCodes = $authorization_codes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         unset($this->authorizationCodes[$code]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         $userDetails = $this->getUserDetails($username); | ||||||
|  |  | ||||||
|  |         return $userDetails && $userDetails['password'] && $userDetails['password'] === $password; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $firstName = null, $lastName = null) | ||||||
|  |     { | ||||||
|  |         $this->userCredentials[$username] = array( | ||||||
|  |             'password'   => $password, | ||||||
|  |             'first_name' => $firstName, | ||||||
|  |             'last_name'  => $lastName, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         if (!isset($this->userCredentials[$username])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array_merge(array( | ||||||
|  |             'user_id'    => $username, | ||||||
|  |             'password'   => null, | ||||||
|  |             'first_name' => null, | ||||||
|  |             'last_name'  => null, | ||||||
|  |         ), $this->userCredentials[$username]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserClaimsInterface */ | ||||||
|  |     public function getUserClaims($user_id, $claims) | ||||||
|  |     { | ||||||
|  |         if (!$userDetails = $this->getUserDetails($user_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $claims = explode(' ', trim($claims)); | ||||||
|  |         $userClaims = array(); | ||||||
|  |  | ||||||
|  |         // for each requested claim, if the user has the claim, set it in the response | ||||||
|  |         $validClaims = explode(' ', self::VALID_CLAIMS); | ||||||
|  |         foreach ($validClaims as $validClaim) { | ||||||
|  |             if (in_array($validClaim, $claims)) { | ||||||
|  |                 if ($validClaim == 'address') { | ||||||
|  |                     // address is an object with subfields | ||||||
|  |                     $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); | ||||||
|  |                 } else { | ||||||
|  |                     $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getUserClaim($claim, $userDetails) | ||||||
|  |     { | ||||||
|  |         $userClaims = array(); | ||||||
|  |         $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); | ||||||
|  |         $claimValues = explode(' ', $claimValuesString); | ||||||
|  |  | ||||||
|  |         foreach ($claimValues as $value) { | ||||||
|  |             $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         return isset($this->clientCredentials[$client_id]['client_secret']) && $this->clientCredentials[$client_id]['client_secret'] === $client_secret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         if (!isset($this->clientCredentials[$client_id])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($this->clientCredentials[$client_id]['client_secret']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         if (!isset($this->clientCredentials[$client_id])) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $clientDetails = array_merge(array( | ||||||
|  |             'client_id'     => $client_id, | ||||||
|  |             'client_secret' => null, | ||||||
|  |             'redirect_uri'  => null, | ||||||
|  |             'scope'         => null, | ||||||
|  |         ), $this->clientCredentials[$client_id]); | ||||||
|  |  | ||||||
|  |         return $clientDetails; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         if (isset($this->clientCredentials[$client_id]['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $this->clientCredentials[$client_id]['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         $this->clientCredentials[$client_id] = array( | ||||||
|  |             'client_id'     => $client_id, | ||||||
|  |             'client_secret' => $client_secret, | ||||||
|  |             'redirect_uri'  => $redirect_uri, | ||||||
|  |             'grant_types'   => $grant_types, | ||||||
|  |             'scope'         => $scope, | ||||||
|  |             'user_id'       => $user_id, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         return isset($this->refreshTokens[$refresh_token]) ? $this->refreshTokens[$refresh_token] : false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         $this->refreshTokens[$refresh_token] = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         if (isset($this->refreshTokens[$refresh_token])) { | ||||||
|  |             unset($this->refreshTokens[$refresh_token]); | ||||||
|  |  | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshTokens($refresh_tokens) | ||||||
|  |     { | ||||||
|  |         $this->refreshTokens = $refresh_tokens; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         return isset($this->accessTokens[$access_token]) ? $this->accessTokens[$access_token] : false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         $this->accessTokens[$access_token] = compact('access_token', 'client_id', 'user_id', 'expires', 'scope', 'id_token'); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         if (isset($this->accessTokens[$access_token])) { | ||||||
|  |             unset($this->accessTokens[$access_token]); | ||||||
|  |  | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         $scope = explode(' ', trim($scope)); | ||||||
|  |  | ||||||
|  |         return (count(array_diff($scope, $this->supportedScopes)) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |         return $this->defaultScope; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*JWTBearerInterface */ | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         if (isset($this->jwt[$client_id])) { | ||||||
|  |             $jwt = $this->jwt[$client_id]; | ||||||
|  |             if ($jwt) { | ||||||
|  |                 if ($jwt["subject"] == $subject) { | ||||||
|  |                     return $jwt["key"]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         foreach ($this->jti as $storedJti) { | ||||||
|  |             if ($storedJti['issuer'] == $client_id && $storedJti['subject'] == $subject && $storedJti['audience'] == $audience && $storedJti['expires'] == $expires && $storedJti['jti'] == $jti) { | ||||||
|  |                 return array( | ||||||
|  |                     'issuer' => $storedJti['issuer'], | ||||||
|  |                     'subject' => $storedJti['subject'], | ||||||
|  |                     'audience' => $storedJti['audience'], | ||||||
|  |                     'expires' => $storedJti['expires'], | ||||||
|  |                     'jti' => $storedJti['jti'] | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         $this->jti[] = array('issuer' => $client_id, 'subject' => $subject, 'audience' => $audience, 'expires' => $expires, 'jti' => $jti); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*PublicKeyInterface */ | ||||||
|  |     public function getPublicKey($client_id = null) | ||||||
|  |     { | ||||||
|  |         if (isset($this->keys[$client_id])) { | ||||||
|  |             return $this->keys[$client_id]['public_key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // use a global encryption pair | ||||||
|  |         if (isset($this->keys['public_key'])) { | ||||||
|  |             return $this->keys['public_key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPrivateKey($client_id = null) | ||||||
|  |     { | ||||||
|  |         if (isset($this->keys[$client_id])) { | ||||||
|  |             return $this->keys[$client_id]['private_key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // use a global encryption pair | ||||||
|  |         if (isset($this->keys['private_key'])) { | ||||||
|  |             return $this->keys['private_key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getEncryptionAlgorithm($client_id = null) | ||||||
|  |     { | ||||||
|  |         if (isset($this->keys[$client_id]['encryption_algorithm'])) { | ||||||
|  |             return $this->keys[$client_id]['encryption_algorithm']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // use a global encryption algorithm | ||||||
|  |         if (isset($this->keys['encryption_algorithm'])) { | ||||||
|  |             return $this->keys['encryption_algorithm']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 'RS256'; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										339
									
								
								library/oauth2/src/OAuth2/Storage/Mongo.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								library/oauth2/src/OAuth2/Storage/Mongo.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,339 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple MongoDB storage for all storage types | ||||||
|  |  * | ||||||
|  |  * NOTE: This class is meant to get users started | ||||||
|  |  * quickly. If your application requires further | ||||||
|  |  * customization, extend this class or create your own. | ||||||
|  |  * | ||||||
|  |  * NOTE: Passwords are stored in plaintext, which is never | ||||||
|  |  * a good idea.  Be sure to override this for your application | ||||||
|  |  * | ||||||
|  |  * @author Julien Chaumond <chaumond@gmail.com> | ||||||
|  |  */ | ||||||
|  | class Mongo implements AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     protected $db; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     public function __construct($connection, $config = array()) | ||||||
|  |     { | ||||||
|  |         if ($connection instanceof \MongoDB) { | ||||||
|  |             $this->db = $connection; | ||||||
|  |         } else { | ||||||
|  |             if (!is_array($connection)) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array'); | ||||||
|  |             } | ||||||
|  |             $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']); | ||||||
|  |             $m = new \MongoClient($server); | ||||||
|  |             $this->db = $m->{$connection['database']}; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'client_table' => 'oauth_clients', | ||||||
|  |             'access_token_table' => 'oauth_access_tokens', | ||||||
|  |             'refresh_token_table' => 'oauth_refresh_tokens', | ||||||
|  |             'code_table' => 'oauth_authorization_codes', | ||||||
|  |             'user_table' => 'oauth_users', | ||||||
|  |             'jwt_table' => 'oauth_jwt', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Helper function to access a MongoDB collection by `type`: | ||||||
|  |     protected function collection($name) | ||||||
|  |     { | ||||||
|  |         return $this->db->{$this->config[$name]}; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { | ||||||
|  |             return $result['client_secret'] == $client_secret; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($result['client_secret']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         $result = $this->collection('client_table')->findOne(array('client_id' => $client_id)); | ||||||
|  |  | ||||||
|  |         return is_null($result) ? false : $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         if ($this->getClientDetails($client_id)) { | ||||||
|  |             $this->collection('client_table')->update( | ||||||
|  |                 array('client_id' => $client_id), | ||||||
|  |                 array('$set' => array( | ||||||
|  |                     'client_secret' => $client_secret, | ||||||
|  |                     'redirect_uri'  => $redirect_uri, | ||||||
|  |                     'grant_types'   => $grant_types, | ||||||
|  |                     'scope'         => $scope, | ||||||
|  |                     'user_id'       => $user_id, | ||||||
|  |                 )) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             $client = array( | ||||||
|  |                 'client_id'     => $client_id, | ||||||
|  |                 'client_secret' => $client_secret, | ||||||
|  |                 'redirect_uri'  => $redirect_uri, | ||||||
|  |                 'grant_types'   => $grant_types, | ||||||
|  |                 'scope'         => $scope, | ||||||
|  |                 'user_id'       => $user_id, | ||||||
|  |             ); | ||||||
|  |             $this->collection('client_table')->insert($client); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token)); | ||||||
|  |  | ||||||
|  |         return is_null($token) ? false : $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAccessToken($access_token)) { | ||||||
|  |             $this->collection('access_token_table')->update( | ||||||
|  |                 array('access_token' => $access_token), | ||||||
|  |                 array('$set' => array( | ||||||
|  |                     'client_id' => $client_id, | ||||||
|  |                     'expires' => $expires, | ||||||
|  |                     'user_id' => $user_id, | ||||||
|  |                     'scope' => $scope | ||||||
|  |                 )) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             $token = array( | ||||||
|  |                 'access_token' => $access_token, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'scope' => $scope | ||||||
|  |             ); | ||||||
|  |             $this->collection('access_token_table')->insert($token); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->collection('access_token_table')->remove(array( | ||||||
|  |             'access_token' => $access_token | ||||||
|  |         ), array('w' => 1)); | ||||||
|  |  | ||||||
|  |         return $result['n'] > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /* AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $code = $this->collection('code_table')->findOne(array('authorization_code' => $code)); | ||||||
|  |  | ||||||
|  |         return is_null($code) ? false : $code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAuthorizationCode($code)) { | ||||||
|  |             $this->collection('code_table')->update( | ||||||
|  |                 array('authorization_code' => $code), | ||||||
|  |                 array('$set' => array( | ||||||
|  |                     'client_id' => $client_id, | ||||||
|  |                     'user_id' => $user_id, | ||||||
|  |                     'redirect_uri' => $redirect_uri, | ||||||
|  |                     'expires' => $expires, | ||||||
|  |                     'scope' => $scope, | ||||||
|  |                     'id_token' => $id_token, | ||||||
|  |                 )) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             $token = array( | ||||||
|  |                 'authorization_code' => $code, | ||||||
|  |                 'client_id' => $client_id, | ||||||
|  |                 'user_id' => $user_id, | ||||||
|  |                 'redirect_uri' => $redirect_uri, | ||||||
|  |                 'expires' => $expires, | ||||||
|  |                 'scope' => $scope, | ||||||
|  |                 'id_token' => $id_token, | ||||||
|  |             ); | ||||||
|  |             $this->collection('code_table')->insert($token); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $this->collection('code_table')->remove(array('authorization_code' => $code)); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             return $this->checkPassword($user, $password); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             $user['user_id'] = $user['username']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $user; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token)); | ||||||
|  |  | ||||||
|  |         return is_null($token) ? false : $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         $token = array( | ||||||
|  |             'refresh_token' => $refresh_token, | ||||||
|  |             'client_id' => $client_id, | ||||||
|  |             'user_id' => $user_id, | ||||||
|  |             'expires' => $expires, | ||||||
|  |             'scope' => $scope | ||||||
|  |         ); | ||||||
|  |         $this->collection('refresh_token_table')->insert($token); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->collection('refresh_token_table')->remove(array( | ||||||
|  |             'refresh_token' => $refresh_token | ||||||
|  |         ), array('w' => 1)); | ||||||
|  |  | ||||||
|  |         return $result['n'] > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // plaintext passwords are bad!  Override this for your application | ||||||
|  |     protected function checkPassword($user, $password) | ||||||
|  |     { | ||||||
|  |         return $user['password'] == $password; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         $result = $this->collection('user_table')->findOne(array('username' => $username)); | ||||||
|  |  | ||||||
|  |         return is_null($result) ? false : $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $firstName = null, $lastName = null) | ||||||
|  |     { | ||||||
|  |         if ($this->getUser($username)) { | ||||||
|  |             $this->collection('user_table')->update( | ||||||
|  |                 array('username' => $username), | ||||||
|  |                 array('$set' => array( | ||||||
|  |                     'password' => $password, | ||||||
|  |                     'first_name' => $firstName, | ||||||
|  |                     'last_name' => $lastName | ||||||
|  |                 )) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             $user = array( | ||||||
|  |                 'username' => $username, | ||||||
|  |                 'password' => $password, | ||||||
|  |                 'first_name' => $firstName, | ||||||
|  |                 'last_name' => $lastName | ||||||
|  |             ); | ||||||
|  |             $this->collection('user_table')->insert($user); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         $result = $this->collection('jwt_table')->findOne(array( | ||||||
|  |             'client_id' => $client_id, | ||||||
|  |             'subject' => $subject | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         return is_null($result) ? false : $result['key']; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs mongodb implementation. | ||||||
|  |         throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs mongodb implementation. | ||||||
|  |         throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										553
									
								
								library/oauth2/src/OAuth2/Storage/Pdo.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										553
									
								
								library/oauth2/src/OAuth2/Storage/Pdo.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,553 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\UserClaimsInterface; | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Simple PDO storage for all storage types | ||||||
|  |  * | ||||||
|  |  * NOTE: This class is meant to get users started | ||||||
|  |  * quickly. If your application requires further | ||||||
|  |  * customization, extend this class or create your own. | ||||||
|  |  * | ||||||
|  |  * NOTE: Passwords are stored in plaintext, which is never | ||||||
|  |  * a good idea.  Be sure to override this for your application | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | class Pdo implements | ||||||
|  |     AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     ScopeInterface, | ||||||
|  |     PublicKeyInterface, | ||||||
|  |     UserClaimsInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |     protected $db; | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     public function __construct($connection, $config = array()) | ||||||
|  |     { | ||||||
|  |         if (!$connection instanceof \PDO) { | ||||||
|  |             if (is_string($connection)) { | ||||||
|  |                 $connection = array('dsn' => $connection); | ||||||
|  |             } | ||||||
|  |             if (!is_array($connection)) { | ||||||
|  |                 throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO, a DSN string, or a configuration array'); | ||||||
|  |             } | ||||||
|  |             if (!isset($connection['dsn'])) { | ||||||
|  |                 throw new \InvalidArgumentException('configuration array must contain "dsn"'); | ||||||
|  |             } | ||||||
|  |             // merge optional parameters | ||||||
|  |             $connection = array_merge(array( | ||||||
|  |                 'username' => null, | ||||||
|  |                 'password' => null, | ||||||
|  |                 'options' => array(), | ||||||
|  |             ), $connection); | ||||||
|  |             $connection = new \PDO($connection['dsn'], $connection['username'], $connection['password'], $connection['options']); | ||||||
|  |         } | ||||||
|  |         $this->db = $connection; | ||||||
|  |  | ||||||
|  |         // debugging | ||||||
|  |         $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); | ||||||
|  |  | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'client_table' => 'oauth_clients', | ||||||
|  |             'access_token_table' => 'oauth_access_tokens', | ||||||
|  |             'refresh_token_table' => 'oauth_refresh_tokens', | ||||||
|  |             'code_table' => 'oauth_authorization_codes', | ||||||
|  |             'user_table' => 'oauth_users', | ||||||
|  |             'jwt_table'  => 'oauth_jwt', | ||||||
|  |             'jti_table'  => 'oauth_jti', | ||||||
|  |             'scope_table'  => 'oauth_scopes', | ||||||
|  |             'public_key_table'  => 'oauth_public_keys', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |         $result = $stmt->fetch(\PDO::FETCH_ASSOC); | ||||||
|  |  | ||||||
|  |         // make this extensible | ||||||
|  |         return $result && $result['client_secret'] == $client_secret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |  | ||||||
|  |         if (!$result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($result['client_secret']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |  | ||||||
|  |         return $stmt->fetch(\PDO::FETCH_ASSOC); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getClientDetails($client_id)) { | ||||||
|  |             $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id where client_id=:client_id', $this->config['client_table'])); | ||||||
|  |         } else { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('INSERT INTO %s (client_id, client_secret, redirect_uri, grant_types, scope, user_id) VALUES (:client_id, :client_secret, :redirect_uri, :grant_types, :scope, :user_id)', $this->config['client_table'])); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, (array) $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table'])); | ||||||
|  |  | ||||||
|  |         $token = $stmt->execute(compact('access_token')); | ||||||
|  |         if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             // convert date string back to timestamp | ||||||
|  |             $token['expires'] = strtotime($token['expires']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAccessToken($access_token)) { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['access_token_table'])); | ||||||
|  |         } else { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table'])); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('access_token')); | ||||||
|  |  | ||||||
|  |         return $stmt->rowCount() > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table'])); | ||||||
|  |         $stmt->execute(compact('code')); | ||||||
|  |  | ||||||
|  |         if ($code = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             // convert date string back to timestamp | ||||||
|  |             $code['expires'] = strtotime($code['expires']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         if (func_num_args() > 6) { | ||||||
|  |             // we are calling with an id token | ||||||
|  |             return call_user_func_array(array($this, 'setAuthorizationCodeWithIdToken'), func_get_args()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAuthorizationCode($code)) { | ||||||
|  |             $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table'])); | ||||||
|  |         } else { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table'])); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getAuthorizationCode($code)) { | ||||||
|  |             $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table'])); | ||||||
|  |         } else { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table'])); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table'])); | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('code')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         if ($user = $this->getUser($username)) { | ||||||
|  |             return $this->checkPassword($user, $password); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         return $this->getUser($username); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserClaimsInterface */ | ||||||
|  |     public function getUserClaims($user_id, $claims) | ||||||
|  |     { | ||||||
|  |         if (!$userDetails = $this->getUserDetails($user_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $claims = explode(' ', trim($claims)); | ||||||
|  |         $userClaims = array(); | ||||||
|  |  | ||||||
|  |         // for each requested claim, if the user has the claim, set it in the response | ||||||
|  |         $validClaims = explode(' ', self::VALID_CLAIMS); | ||||||
|  |         foreach ($validClaims as $validClaim) { | ||||||
|  |             if (in_array($validClaim, $claims)) { | ||||||
|  |                 if ($validClaim == 'address') { | ||||||
|  |                     // address is an object with subfields | ||||||
|  |                     $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); | ||||||
|  |                 } else { | ||||||
|  |                     $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getUserClaim($claim, $userDetails) | ||||||
|  |     { | ||||||
|  |         $userClaims = array(); | ||||||
|  |         $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); | ||||||
|  |         $claimValues = explode(' ', $claimValuesString); | ||||||
|  |  | ||||||
|  |         foreach ($claimValues as $value) { | ||||||
|  |             $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $userClaims; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* OAuth2\Storage\RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); | ||||||
|  |  | ||||||
|  |         $token = $stmt->execute(compact('refresh_token')); | ||||||
|  |         if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             // convert expires to epoch time | ||||||
|  |             $token['expires'] = strtotime($token['expires']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         // convert expires to datestring | ||||||
|  |         $expires = date('Y-m-d H:i:s', $expires); | ||||||
|  |  | ||||||
|  |         $stmt = $this->db->prepare(sprintf('INSERT INTO %s (refresh_token, client_id, user_id, expires, scope) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table'])); | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('refresh_token')); | ||||||
|  |  | ||||||
|  |         return $stmt->rowCount() > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // plaintext passwords are bad!  Override this for your application | ||||||
|  |     protected function checkPassword($user, $password) | ||||||
|  |     { | ||||||
|  |         return $user['password'] == $this->hashPassword($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // use a secure hashing algorithm when storing passwords. Override this for your application | ||||||
|  |     protected function hashPassword($password) | ||||||
|  |     { | ||||||
|  |         return sha1($password); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table'])); | ||||||
|  |         $stmt->execute(array('username' => $username)); | ||||||
|  |  | ||||||
|  |         if (!$userInfo = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the default behavior is to use "username" as the user_id | ||||||
|  |         return array_merge(array( | ||||||
|  |             'user_id' => $username | ||||||
|  |         ), $userInfo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $firstName = null, $lastName = null) | ||||||
|  |     { | ||||||
|  |         // do not store in plaintext | ||||||
|  |         $password = $this->hashPassword($password); | ||||||
|  |  | ||||||
|  |         // if it exists, update it. | ||||||
|  |         if ($this->getUser($username)) { | ||||||
|  |             $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table'])); | ||||||
|  |         } else { | ||||||
|  |             $stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table'])); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('username', 'password', 'firstName', 'lastName')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ScopeInterface */ | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         $scope = explode(' ', $scope); | ||||||
|  |         $whereIn = implode(',', array_fill(0, count($scope), '?')); | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT count(scope) as count FROM %s WHERE scope IN (%s)', $this->config['scope_table'], $whereIn)); | ||||||
|  |         $stmt->execute($scope); | ||||||
|  |  | ||||||
|  |         if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return $result['count'] == count($scope); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table'])); | ||||||
|  |         $stmt->execute(array('is_default' => true)); | ||||||
|  |  | ||||||
|  |         if ($result = $stmt->fetchAll(\PDO::FETCH_ASSOC)) { | ||||||
|  |             $defaultScope = array_map(function ($row) { | ||||||
|  |                 return $row['scope']; | ||||||
|  |             }, $result); | ||||||
|  |  | ||||||
|  |             return implode(' ', $defaultScope); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* JWTBearerInterface */ | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(array('client_id' => $client_id, 'subject' => $subject)); | ||||||
|  |  | ||||||
|  |         return $stmt->fetchColumn(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti')); | ||||||
|  |  | ||||||
|  |         if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return array( | ||||||
|  |                 'issuer' => $result['issuer'], | ||||||
|  |                 'subject' => $result['subject'], | ||||||
|  |                 'audience' => $result['audience'], | ||||||
|  |                 'expires' => $result['expires'], | ||||||
|  |                 'jti' => $result['jti'], | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expires, $jti) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table'])); | ||||||
|  |  | ||||||
|  |         return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* PublicKeyInterface */ | ||||||
|  |     public function getPublicKey($client_id = null) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |         if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return $result['public_key']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPrivateKey($client_id = null) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |         if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return $result['private_key']; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getEncryptionAlgorithm($client_id = null) | ||||||
|  |     { | ||||||
|  |         $stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); | ||||||
|  |  | ||||||
|  |         $stmt->execute(compact('client_id')); | ||||||
|  |         if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { | ||||||
|  |             return $result['encryption_algorithm']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 'RS256'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * DDL to create OAuth2 database and tables for PDO storage | ||||||
|  |      * | ||||||
|  |      * @see https://github.com/dsquier/oauth2-server-php-mysql | ||||||
|  |      */ | ||||||
|  |     public function getBuildSql($dbName = 'oauth2_server_php') | ||||||
|  |     { | ||||||
|  |         $sql = " | ||||||
|  |         CREATE TABLE {$this->config['client_table']} ( | ||||||
|  |           client_id             VARCHAR(80)   NOT NULL, | ||||||
|  |           client_secret         VARCHAR(80), | ||||||
|  |           redirect_uri          VARCHAR(2000), | ||||||
|  |           grant_types           VARCHAR(80), | ||||||
|  |           scope                 VARCHAR(4000), | ||||||
|  |           user_id               VARCHAR(80), | ||||||
|  |           PRIMARY KEY (client_id) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['access_token_table']} ( | ||||||
|  |           access_token         VARCHAR(40)    NOT NULL, | ||||||
|  |           client_id            VARCHAR(80)    NOT NULL, | ||||||
|  |           user_id              VARCHAR(80), | ||||||
|  |           expires              TIMESTAMP      NOT NULL, | ||||||
|  |           scope                VARCHAR(4000), | ||||||
|  |           PRIMARY KEY (access_token) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['code_table']} ( | ||||||
|  |           authorization_code  VARCHAR(40)    NOT NULL, | ||||||
|  |           client_id           VARCHAR(80)    NOT NULL, | ||||||
|  |           user_id             VARCHAR(80), | ||||||
|  |           redirect_uri        VARCHAR(2000), | ||||||
|  |           expires             TIMESTAMP      NOT NULL, | ||||||
|  |           scope               VARCHAR(4000), | ||||||
|  |           id_token            VARCHAR(1000), | ||||||
|  |           PRIMARY KEY (authorization_code) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['refresh_token_table']} ( | ||||||
|  |           refresh_token       VARCHAR(40)    NOT NULL, | ||||||
|  |           client_id           VARCHAR(80)    NOT NULL, | ||||||
|  |           user_id             VARCHAR(80), | ||||||
|  |           expires             TIMESTAMP      NOT NULL, | ||||||
|  |           scope               VARCHAR(4000), | ||||||
|  |           PRIMARY KEY (refresh_token) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['user_table']} ( | ||||||
|  |           username            VARCHAR(80), | ||||||
|  |           password            VARCHAR(80), | ||||||
|  |           first_name          VARCHAR(80), | ||||||
|  |           last_name           VARCHAR(80), | ||||||
|  |           email               VARCHAR(80), | ||||||
|  |           email_verified      BOOLEAN, | ||||||
|  |           scope               VARCHAR(4000) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['scope_table']} ( | ||||||
|  |           scope               VARCHAR(80)  NOT NULL, | ||||||
|  |           is_default          BOOLEAN, | ||||||
|  |           PRIMARY KEY (scope) | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['jwt_table']} ( | ||||||
|  |           client_id           VARCHAR(80)   NOT NULL, | ||||||
|  |           subject             VARCHAR(80), | ||||||
|  |           public_key          VARCHAR(2000) NOT NULL | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['jti_table']} ( | ||||||
|  |           issuer              VARCHAR(80)   NOT NULL, | ||||||
|  |           subject             VARCHAR(80), | ||||||
|  |           audience            VARCHAR(80), | ||||||
|  |           expires             TIMESTAMP     NOT NULL, | ||||||
|  |           jti                 VARCHAR(2000) NOT NULL | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         CREATE TABLE {$this->config['public_key_table']} ( | ||||||
|  |           client_id            VARCHAR(80), | ||||||
|  |           public_key           VARCHAR(2000), | ||||||
|  |           private_key          VARCHAR(2000), | ||||||
|  |           encryption_algorithm VARCHAR(100) DEFAULT 'RS256' | ||||||
|  |         ) | ||||||
|  | "; | ||||||
|  |  | ||||||
|  |         return $sql; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get public/private key information | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface PublicKeyInterface | ||||||
|  | { | ||||||
|  |     public function getPublicKey($client_id = null); | ||||||
|  |     public function getPrivateKey($client_id = null); | ||||||
|  |     public function getEncryptionAlgorithm($client_id = null); | ||||||
|  | } | ||||||
							
								
								
									
										321
									
								
								library/oauth2/src/OAuth2/Storage/Redis.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								library/oauth2/src/OAuth2/Storage/Redis.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * redis storage for all storage types | ||||||
|  |  * | ||||||
|  |  * To use, install "predis/predis" via composer | ||||||
|  |  * | ||||||
|  |  * Register client: | ||||||
|  |  * <code> | ||||||
|  |  *  $storage = new OAuth2\Storage\Redis($redis); | ||||||
|  |  *  $storage->setClientDetails($client_id, $client_secret, $redirect_uri); | ||||||
|  |  * </code> | ||||||
|  |  */ | ||||||
|  | class Redis implements AuthorizationCodeInterface, | ||||||
|  |     AccessTokenInterface, | ||||||
|  |     ClientCredentialsInterface, | ||||||
|  |     UserCredentialsInterface, | ||||||
|  |     RefreshTokenInterface, | ||||||
|  |     JwtBearerInterface, | ||||||
|  |     ScopeInterface, | ||||||
|  |     OpenIDAuthorizationCodeInterface | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private $cache; | ||||||
|  |  | ||||||
|  |     /* The redis client */ | ||||||
|  |     protected $redis; | ||||||
|  |  | ||||||
|  |     /* Configuration array */ | ||||||
|  |     protected $config; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Redis Storage! | ||||||
|  |      * | ||||||
|  |      * @param \Predis\Client $redis | ||||||
|  |      * @param array          $config | ||||||
|  |      */ | ||||||
|  |     public function __construct($redis, $config=array()) | ||||||
|  |     { | ||||||
|  |         $this->redis = $redis; | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'client_key' => 'oauth_clients:', | ||||||
|  |             'access_token_key' => 'oauth_access_tokens:', | ||||||
|  |             'refresh_token_key' => 'oauth_refresh_tokens:', | ||||||
|  |             'code_key' => 'oauth_authorization_codes:', | ||||||
|  |             'user_key' => 'oauth_users:', | ||||||
|  |             'jwt_key' => 'oauth_jwt:', | ||||||
|  |             'scope_key' => 'oauth_scopes:', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getValue($key) | ||||||
|  |     { | ||||||
|  |         if ( isset($this->cache[$key]) ) { | ||||||
|  |             return $this->cache[$key]; | ||||||
|  |         } | ||||||
|  |         $value = $this->redis->get($key); | ||||||
|  |         if ( isset($value) ) { | ||||||
|  |             return json_decode($value, true); | ||||||
|  |         } else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function setValue($key, $value, $expire=0) | ||||||
|  |     { | ||||||
|  |         $this->cache[$key] = $value; | ||||||
|  |         $str = json_encode($value); | ||||||
|  |         if ($expire > 0) { | ||||||
|  |             $seconds = $expire - time(); | ||||||
|  |             $ret = $this->redis->setex($key, $seconds, $str); | ||||||
|  |         } else { | ||||||
|  |             $ret = $this->redis->set($key, $str); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // check that the key was set properly | ||||||
|  |         // if this fails, an exception will usually thrown, so this step isn't strictly necessary | ||||||
|  |         return is_bool($ret) ? $ret : $ret->getPayload() == 'OK'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function expireValue($key) | ||||||
|  |     { | ||||||
|  |         unset($this->cache[$key]); | ||||||
|  |  | ||||||
|  |         return $this->redis->del($key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AuthorizationCodeInterface */ | ||||||
|  |     public function getAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['code_key'] . $code); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['code_key'] . $authorization_code, | ||||||
|  |             compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function expireAuthorizationCode($code) | ||||||
|  |     { | ||||||
|  |         $key = $this->config['code_key'] . $code; | ||||||
|  |         unset($this->cache[$key]); | ||||||
|  |  | ||||||
|  |         return $this->expireValue($key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* UserCredentialsInterface */ | ||||||
|  |     public function checkUserCredentials($username, $password) | ||||||
|  |     { | ||||||
|  |         $user = $this->getUserDetails($username); | ||||||
|  |  | ||||||
|  |         return $user && $user['password'] === $password; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserDetails($username) | ||||||
|  |     { | ||||||
|  |         return $this->getUser($username); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUser($username) | ||||||
|  |     { | ||||||
|  |         if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the default behavior is to use "username" as the user_id | ||||||
|  |         return array_merge(array( | ||||||
|  |             'user_id' => $username, | ||||||
|  |         ), $userInfo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setUser($username, $password, $first_name = null, $last_name = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['user_key'] . $username, | ||||||
|  |             compact('username', 'password', 'first_name', 'last_name') | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientCredentialsInterface */ | ||||||
|  |     public function checkClientCredentials($client_id, $client_secret = null) | ||||||
|  |     { | ||||||
|  |         if (!$client = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return isset($client['client_secret']) | ||||||
|  |             && $client['client_secret'] == $client_secret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isPublicClient($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$client = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return empty($client['client_secret']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ClientInterface */ | ||||||
|  |     public function getClientDetails($client_id) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['client_key'] . $client_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['client_key'] . $client_id, | ||||||
|  |             compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function checkRestrictedGrantType($client_id, $grant_type) | ||||||
|  |     { | ||||||
|  |         $details = $this->getClientDetails($client_id); | ||||||
|  |         if (isset($details['grant_types'])) { | ||||||
|  |             $grant_types = explode(' ', $details['grant_types']); | ||||||
|  |  | ||||||
|  |             return in_array($grant_type, (array) $grant_types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if grant_types are not defined, then none are restricted | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* RefreshTokenInterface */ | ||||||
|  |     public function getRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['refresh_token_key'] . $refresh_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['refresh_token_key'] . $refresh_token, | ||||||
|  |             compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetRefreshToken($refresh_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->expireValue($this->config['refresh_token_key'] . $refresh_token); | ||||||
|  |  | ||||||
|  |         return $result > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* AccessTokenInterface */ | ||||||
|  |     public function getAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         return $this->getValue($this->config['access_token_key'].$access_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue( | ||||||
|  |             $this->config['access_token_key'].$access_token, | ||||||
|  |             compact('access_token', 'client_id', 'user_id', 'expires', 'scope'), | ||||||
|  |             $expires | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unsetAccessToken($access_token) | ||||||
|  |     { | ||||||
|  |         $result = $this->expireValue($this->config['access_token_key'] . $access_token); | ||||||
|  |  | ||||||
|  |         return $result > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* ScopeInterface */ | ||||||
|  |     public function scopeExists($scope) | ||||||
|  |     { | ||||||
|  |         $scope = explode(' ', $scope); | ||||||
|  |  | ||||||
|  |         $result = $this->getValue($this->config['scope_key'].'supported:global'); | ||||||
|  |  | ||||||
|  |         $supportedScope = explode(' ', (string) $result); | ||||||
|  |  | ||||||
|  |         return (count(array_diff($scope, $supportedScope)) == 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDefaultScope($client_id = null) | ||||||
|  |     { | ||||||
|  |         if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) { | ||||||
|  |             $result = $this->getValue($this->config['scope_key'].'default:global'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setScope($scope, $client_id = null, $type = 'supported') | ||||||
|  |     { | ||||||
|  |         if (!in_array($type, array('default', 'supported'))) { | ||||||
|  |             throw new \InvalidArgumentException('"$type" must be one of "default", "supported"'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (is_null($client_id)) { | ||||||
|  |             $key = $this->config['scope_key'].$type.':global'; | ||||||
|  |         } else { | ||||||
|  |             $key = $this->config['scope_key'].$type.':'.$client_id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->setValue($key, $scope); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /*JWTBearerInterface */ | ||||||
|  |     public function getClientKey($client_id, $subject) | ||||||
|  |     { | ||||||
|  |         if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($jwt['subject']) && $jwt['subject'] == $subject) { | ||||||
|  |             return $jwt['key']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setClientKey($client_id, $key, $subject = null) | ||||||
|  |     { | ||||||
|  |         return $this->setValue($this->config['jwt_key'] . $client_id, array( | ||||||
|  |             'key' => $key, | ||||||
|  |             'subject' => $subject | ||||||
|  |         )); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getClientScope($client_id) | ||||||
|  |     { | ||||||
|  |         if (!$clientDetails = $this->getClientDetails($client_id)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isset($clientDetails['scope'])) { | ||||||
|  |             return $clientDetails['scope']; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs redis implementation. | ||||||
|  |         throw new \Exception('getJti() for the Redis driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setJti($client_id, $subject, $audience, $expiration, $jti) | ||||||
|  |     { | ||||||
|  |         //TODO: Needs redis implementation. | ||||||
|  |         throw new \Exception('setJti() for the Redis driver is currently unimplemented.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should get/save refresh tokens for the "Refresh Token" | ||||||
|  |  * grant type | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface RefreshTokenInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Grant refresh access tokens. | ||||||
|  |      * | ||||||
|  |      * Retrieve the stored data for the given refresh token. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. | ||||||
|  |      * | ||||||
|  |      * @param $refresh_token | ||||||
|  |      * Refresh token to be check with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * An associative array as below, and NULL if the refresh_token is | ||||||
|  |      * invalid: | ||||||
|  |      * - refresh_token: Refresh token identifier. | ||||||
|  |      * - client_id: Client identifier. | ||||||
|  |      * - user_id: User identifier. | ||||||
|  |      * - expires: Expiration unix timestamp, or 0 if the token doesn't expire. | ||||||
|  |      * - scope: (optional) Scope values in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-6 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_6 | ||||||
|  |      */ | ||||||
|  |     public function getRefreshToken($refresh_token); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Take the provided refresh token values and store them somewhere. | ||||||
|  |      * | ||||||
|  |      * This function should be the storage counterpart to getRefreshToken(). | ||||||
|  |      * | ||||||
|  |      * If storage fails for some reason, we're not currently checking for | ||||||
|  |      * any sort of success/failure, so you should bail out of the script | ||||||
|  |      * and provide a descriptive fail message. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. | ||||||
|  |      * | ||||||
|  |      * @param $refresh_token | ||||||
|  |      * Refresh token to be stored. | ||||||
|  |      * @param $client_id | ||||||
|  |      * Client identifier to be stored. | ||||||
|  |      * @param $user_id | ||||||
|  |      * User identifier to be stored. | ||||||
|  |      * @param $expires | ||||||
|  |      * Expiration timestamp to be stored. 0 if the token doesn't expire. | ||||||
|  |      * @param $scope | ||||||
|  |      * (optional) Scopes to be stored in space-separated string. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_6 | ||||||
|  |      */ | ||||||
|  |     public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Expire a used refresh token. | ||||||
|  |      * | ||||||
|  |      * This is not explicitly required in the spec, but is almost implied. | ||||||
|  |      * After granting a new refresh token, the old one is no longer useful and | ||||||
|  |      * so should be forcibly expired in the data store so it can't be used again. | ||||||
|  |      * | ||||||
|  |      * If storage fails for some reason, we're not currently checking for | ||||||
|  |      * any sort of success/failure, so you should bail out of the script | ||||||
|  |      * and provide a descriptive fail message. | ||||||
|  |      * | ||||||
|  |      * @param $refresh_token | ||||||
|  |      * Refresh token to be expirse. | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_6 | ||||||
|  |      */ | ||||||
|  |     public function unsetRefreshToken($refresh_token); | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								library/oauth2/src/OAuth2/Storage/ScopeInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								library/oauth2/src/OAuth2/Storage/ScopeInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should retrieve data involving the relevent scopes associated | ||||||
|  |  * with this implementation. | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface ScopeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Check if the provided scope exists. | ||||||
|  |      * | ||||||
|  |      * @param $scope | ||||||
|  |      * A space-separated string of scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if it exists, FALSE otherwise. | ||||||
|  |      */ | ||||||
|  |     public function scopeExists($scope); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The default scope to use in the event the client | ||||||
|  |      * does not request one. By returning "false", a | ||||||
|  |      * request_error is returned by the server to force a | ||||||
|  |      * scope request by the client. By returning "null", | ||||||
|  |      * opt out of requiring scopes | ||||||
|  |      * | ||||||
|  |      * @param $client_id | ||||||
|  |      * An optional client id that can be used to return customized default scopes. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * string representation of default scope, null if | ||||||
|  |      * scopes are not defined, or false to force scope | ||||||
|  |      * request by the client | ||||||
|  |      * | ||||||
|  |      * ex: | ||||||
|  |      *     'default' | ||||||
|  |      * ex: | ||||||
|  |      *     null | ||||||
|  |      */ | ||||||
|  |     public function getDefaultScope($client_id = null); | ||||||
|  | } | ||||||
| @@ -0,0 +1,52 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Implement this interface to specify where the OAuth2 Server | ||||||
|  |  * should retrieve user credentials for the | ||||||
|  |  * "Resource Owner Password Credentials" grant type | ||||||
|  |  * | ||||||
|  |  * @author Brent Shaffer <bshafs at gmail dot com> | ||||||
|  |  */ | ||||||
|  | interface UserCredentialsInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Grant access tokens for basic user credentials. | ||||||
|  |      * | ||||||
|  |      * Check the supplied username and password for validity. | ||||||
|  |      * | ||||||
|  |      * You can also use the $client_id param to do any checks required based | ||||||
|  |      * on a client, if you need that. | ||||||
|  |      * | ||||||
|  |      * Required for OAuth2::GRANT_TYPE_USER_CREDENTIALS. | ||||||
|  |      * | ||||||
|  |      * @param $username | ||||||
|  |      * Username to be check with. | ||||||
|  |      * @param $password | ||||||
|  |      * Password to be check with. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      * TRUE if the username and password are valid, and FALSE if it isn't. | ||||||
|  |      * Moreover, if the username and password are valid, and you want to | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.3 | ||||||
|  |      * | ||||||
|  |      * @ingroup oauth2_section_4 | ||||||
|  |      */ | ||||||
|  |     public function checkUserCredentials($username, $password); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return | ||||||
|  |      * ARRAY the associated "user_id" and optional "scope" values | ||||||
|  |      * This function MUST return FALSE if the requested user does not exist or is | ||||||
|  |      * invalid. "scope" is a space-separated list of restricted scopes. | ||||||
|  |      * @code | ||||||
|  |      * return array( | ||||||
|  |      *     "user_id"  => USER_ID,    // REQUIRED user_id to be stored with the authorization code or access token | ||||||
|  |      *     "scope"    => SCOPE       // OPTIONAL space-separated list of restricted scopes | ||||||
|  |      * ); | ||||||
|  |      * @endcode | ||||||
|  |      */ | ||||||
|  |     public function getUserDetails($username); | ||||||
|  | } | ||||||
							
								
								
									
										130
									
								
								library/oauth2/src/OAuth2/TokenType/Bearer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								library/oauth2/src/OAuth2/TokenType/Bearer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\TokenType; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | * | ||||||
|  | */ | ||||||
|  | class Bearer implements TokenTypeInterface | ||||||
|  | { | ||||||
|  |     private $config; | ||||||
|  |  | ||||||
|  |     public function __construct(array $config = array()) | ||||||
|  |     { | ||||||
|  |         $this->config = array_merge(array( | ||||||
|  |             'token_param_name'         => 'access_token', | ||||||
|  |             'token_bearer_header_name' => 'Bearer', | ||||||
|  |         ), $config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getTokenType() | ||||||
|  |     { | ||||||
|  |         return 'Bearer'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if the request has supplied token | ||||||
|  |      * | ||||||
|  |      * @see https://github.com/bshaffer/oauth2-server-php/issues/349#issuecomment-37993588 | ||||||
|  |      */ | ||||||
|  |     public function requestHasToken(RequestInterface $request) | ||||||
|  |     { | ||||||
|  |         $headers = $request->headers('AUTHORIZATION'); | ||||||
|  |  | ||||||
|  |         // check the header, then the querystring, then the request body | ||||||
|  |         return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * This is a convenience function that can be used to get the token, which can then | ||||||
|  |      * be passed to getAccessTokenData(). The constraints specified by the draft are | ||||||
|  |      * attempted to be adheared to in this method. | ||||||
|  |      * | ||||||
|  |      * As per the Bearer spec (draft 8, section 2) - there are three ways for a client | ||||||
|  |      * to specify the bearer token, in order of preference: Authorization Header, | ||||||
|  |      * POST and GET. | ||||||
|  |      * | ||||||
|  |      * NB: Resource servers MUST accept tokens via the Authorization scheme | ||||||
|  |      * (http://tools.ietf.org/html/rfc6750#section-2). | ||||||
|  |      * | ||||||
|  |      * @todo Should we enforce TLS/SSL in this function? | ||||||
|  |      * | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6750#section-2.1 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6750#section-2.2 | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6750#section-2.3 | ||||||
|  |      * | ||||||
|  |      * Old Android version bug (at least with version 2.2) | ||||||
|  |      * @see http://code.google.com/p/android/issues/detail?id=6684 | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         $headers = $request->headers('AUTHORIZATION'); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Ensure more than one method is not used for including an | ||||||
|  |          * access token | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6750#section-3.1 | ||||||
|  |          */ | ||||||
|  |         $methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name'])); | ||||||
|  |         if ($methodsUsed > 1) { | ||||||
|  |             $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * If no authentication is provided, set the status code | ||||||
|  |          * to 401 and return no other error information | ||||||
|  |          * | ||||||
|  |          * @see http://tools.ietf.org/html/rfc6750#section-3.1 | ||||||
|  |          */ | ||||||
|  |         if ($methodsUsed == 0) { | ||||||
|  |             $response->setStatusCode(401); | ||||||
|  |  | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // HEADER: Get the access token from the header | ||||||
|  |         if (!empty($headers)) { | ||||||
|  |             if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\s(\S+)/i', $headers, $matches)) { | ||||||
|  |                 $response->setError(400, 'invalid_request', 'Malformed auth header'); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return $matches[1]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($request->request($this->config['token_param_name'])) { | ||||||
|  |             // // POST: Get the token from POST data | ||||||
|  |             if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) { | ||||||
|  |                 $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2'); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $contentType = $request->server('CONTENT_TYPE'); | ||||||
|  |             if (false !== $pos = strpos($contentType, ';')) { | ||||||
|  |                 $contentType = substr($contentType, 0, $pos); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') { | ||||||
|  |                 // IETF specifies content-type. NB: Not all webservers populate this _SERVER variable | ||||||
|  |                 // @see http://tools.ietf.org/html/rfc6750#section-2.2 | ||||||
|  |                 $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"'); | ||||||
|  |  | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return $request->request($this->config['token_param_name']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // GET method | ||||||
|  |         return $request->query($this->config['token_param_name']); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								library/oauth2/src/OAuth2/TokenType/Mac.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								library/oauth2/src/OAuth2/TokenType/Mac.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\TokenType; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | * This is not yet supported! | ||||||
|  | */ | ||||||
|  | class Mac implements TokenTypeInterface | ||||||
|  | { | ||||||
|  |     public function getTokenType() | ||||||
|  |     { | ||||||
|  |         return 'mac'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) | ||||||
|  |     { | ||||||
|  |         throw new \LogicException("Not supported"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\TokenType; | ||||||
|  |  | ||||||
|  | use OAuth2\RequestInterface; | ||||||
|  | use OAuth2\ResponseInterface; | ||||||
|  |  | ||||||
|  | interface TokenTypeInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Token type identification string | ||||||
|  |      * | ||||||
|  |      * ex: "bearer" or "mac" | ||||||
|  |      */ | ||||||
|  |     public function getTokenType(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieves the token string from the request object | ||||||
|  |      */ | ||||||
|  |     public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response); | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								library/oauth2/test/OAuth2/AutoloadTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								library/oauth2/test/OAuth2/AutoloadTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | class AutoloadTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testClassesExist() | ||||||
|  |     { | ||||||
|  |         // autoloader is called in test/bootstrap.php | ||||||
|  |         $this->assertTrue(class_exists('OAuth2\Server')); | ||||||
|  |         $this->assertTrue(class_exists('OAuth2\Request')); | ||||||
|  |         $this->assertTrue(class_exists('OAuth2\Response')); | ||||||
|  |         $this->assertTrue(class_exists('OAuth2\GrantType\UserCredentials')); | ||||||
|  |         $this->assertTrue(interface_exists('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,492 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Memory; | ||||||
|  | use OAuth2\Scope; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\GrantType\AuthorizationCode; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  |  | ||||||
|  | class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testNoClientIdResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'No client id supplied'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidClientIdResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Fake Client ID', // invalid client id | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The client id supplied is invalid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoRedirectUriSuppliedOrStoredResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_uri'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'No redirect URI was supplied or stored'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoResponseTypeResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'invalid_request'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'Invalid or missing response type'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidResponseTypeResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'invalid', // invalid response type | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'invalid_request'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'Invalid or missing response type'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRedirectUriFragmentResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com#fragment', // valid redirect URI | ||||||
|  |             'response_type' => 'code', // invalid response type | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_uri'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The redirect URI must not contain a fragment'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testEnforceState() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('enforce_state' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'invalid_request'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'The state parameter is required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testDoNotEnforceState() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('enforce_state' => false)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertNotContains('error', $response->getHttpHeader('Location')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testEnforceScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $scopeStorage = new Memory(array('default_scope' => false, 'supported_scopes' => array('testscope'))); | ||||||
|  |         $server->setScopeUtil(new Scope($scopeStorage)); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state' => 'xyz', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'invalid_client'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'This application requires you specify a scope parameter'); | ||||||
|  |  | ||||||
|  |         $request->query['scope'] = 'testscope'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertNotContains('error', $response->getHttpHeader('Location')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidRedirectUri() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID with Redirect Uri', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // invalid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidRedirectUriApprovedByBuggyRegisteredUri() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->setConfig('require_exact_redirect_uri', false); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID with Buggy Redirect Uri', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // invalid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoRedirectUriWithMultipleRedirectUris() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         // create a request with no "redirect_uri" in querystring | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID with Multiple Redirect Uris', // valid client id | ||||||
|  |             'response_type' => 'code', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_uri'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'A redirect URI must be supplied when multiple redirect URIs are registered'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRedirectUriWithValidRedirectUri() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         // create a request with no "redirect_uri" in querystring | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID with Redirect Uri Parts', // valid client id | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'redirect_uri'  => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertContains('code', $response->getHttpHeader('Location')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRedirectUriWithDifferentQueryAndExactMatchRequired() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('require_exact_redirect_uri' => true)); | ||||||
|  |  | ||||||
|  |         // create a request with no "redirect_uri" in querystring | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRedirectUriWithDifferentQueryAndExactMatchNotRequired() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('require_exact_redirect_uri' => false)); | ||||||
|  |  | ||||||
|  |         // create a request with no "redirect_uri" in querystring | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID with Redirect Uri Parts', // valid client id | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'redirect_uri'  => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertContains('code', $response->getHttpHeader('Location')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMultipleRedirectUris() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID with Multiple Redirect Uris', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://brentertainment.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'xyz' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertContains('code', $response->getHttpHeader('Location')); | ||||||
|  |  | ||||||
|  |         // call again with different (but still valid) redirect URI | ||||||
|  |         $request->query['redirect_uri'] = 'http://morehazards.com'; | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertContains('code', $response->getHttpHeader('Location')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 | ||||||
|  |      * @see https://github.com/bshaffer/oauth2-server-php/issues/163 | ||||||
|  |      */ | ||||||
|  |     public function testNoRedirectUriSuppliedDoesNotRequireTokenRedirectUri() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID with Redirect Uri', // valid client id | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertContains('state', $response->getHttpHeader('Location')); | ||||||
|  |         $this->assertStringStartsWith('http://brentertainment.com?code=', $response->getHttpHeader('Location')); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         // call token endpoint with no redirect_uri supplied | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'client_id'     => 'Test Client ID with Redirect Uri', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret2', | ||||||
|  |             'grant_type'    => 'authorization_code', | ||||||
|  |             'code'          => $query['code'], | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response(), true); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUserDeniesAccessResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state' => 'xyz', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'access_denied'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'The user denied access to your application'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCodeQueryParamIsSet() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri | ||||||
|  |         $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['fragment'])); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |         $this->assertNotNull($query); | ||||||
|  |         $this->assertArrayHasKey('code', $query); | ||||||
|  |  | ||||||
|  |         // ensure no id_token was saved, since the openid scope wasn't requested | ||||||
|  |         $storage = $server->getStorage('authorization_code'); | ||||||
|  |         $code = $storage->getAuthorizationCode($query['code']); | ||||||
|  |         $this->assertTrue(empty($code['id_token'])); | ||||||
|  |  | ||||||
|  |         // ensure no error was returned | ||||||
|  |         $this->assertFalse(isset($query['error'])); | ||||||
|  |         $this->assertFalse(isset($query['error_description'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulRequestReturnsStateParameter() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'test', // valid state string (just needs to be passed back to us) | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertEquals($query['state'], 'test'); | ||||||
|  |  | ||||||
|  |         // ensure no error was returned | ||||||
|  |         $this->assertFalse(isset($query['error'])); | ||||||
|  |         $this->assertFalse(isset($query['error_description'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulRequestStripsExtraParameters() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'test',      // valid state string (just needs to be passed back to us) | ||||||
|  |             'fake'          => 'something', // extra query param | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertFalse(isset($parts['fake'])); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertFalse(isset($parmas['fake'])); | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertEquals($query['state'], 'test'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulOpenidConnectRequest() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'bojanz', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |             'scope'         => 'openid', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['fragment'])); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |         $this->assertNotNull($query); | ||||||
|  |         $this->assertArrayHasKey('code', $query); | ||||||
|  |  | ||||||
|  |         // ensure no error was returned | ||||||
|  |         $this->assertFalse(isset($query['error'])); | ||||||
|  |         $this->assertFalse(isset($query['error_description'])); | ||||||
|  |  | ||||||
|  |         // confirm that the id_token has been created. | ||||||
|  |         $storage = $server->getStorage('authorization_code'); | ||||||
|  |         $code = $storage->getAuthorizationCode($query['code']); | ||||||
|  |         $this->assertTrue(!empty($code['id_token'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCreateController() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $controller = new AuthorizeController($storage); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         // Add the two types supported for authorization grant | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										175
									
								
								library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\GrantType\AuthorizationCode; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class ResourceControllerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testNoAccessToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMalformedHeader() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'tH1s i5 B0gU5'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Malformed auth header'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMultipleTokensSubmitted() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->request['access_token'] = 'TEST'; | ||||||
|  |         $request->query['access_token'] = 'TEST'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidRequestMethod() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->server['REQUEST_METHOD'] = 'GET'; | ||||||
|  |         $request->request['access_token'] = 'TEST'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'When putting the token in the body, the method must be POST or PUT'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidContentType() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->server['REQUEST_METHOD'] = 'POST'; | ||||||
|  |         $request->server['CONTENT_TYPE'] = 'application/json'; | ||||||
|  |         $request->request['access_token'] = 'TEST'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer TESTTOKEN'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_token'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The access token provided is invalid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testExpiredToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-expired'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'expired_token'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The access token provided has expired'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testOutOfScopeToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; | ||||||
|  |         $scope = 'outofscope'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response(), $scope); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 403); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'insufficient_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The request requires higher privileges than provided by the access token'); | ||||||
|  |  | ||||||
|  |         // verify the "scope" has been set in the "WWW-Authenticate" header | ||||||
|  |         preg_match('/scope="(.*?)"/', $response->getHttpHeader('WWW-Authenticate'), $matches); | ||||||
|  |         $this->assertEquals(2, count($matches)); | ||||||
|  |         $this->assertEquals($matches[1], 'outofscope'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMalformedToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-malformed'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertFalse($allow); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'malformed_token'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Malformed token (missing "expires")'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertTrue($allow); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidTokenWithScopeParam() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; | ||||||
|  |         $request->query['scope'] = 'testscope'; | ||||||
|  |         $allow = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         $this->assertTrue($allow); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCreateController() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $tokenType = new \OAuth2\TokenType\Bearer(); | ||||||
|  |         $controller = new ResourceController($tokenType, $storage); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         // Add the two types supported for authorization grant | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										289
									
								
								library/oauth2/test/OAuth2/Controller/TokenControllerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								library/oauth2/test/OAuth2/Controller/TokenControllerTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\GrantType\AuthorizationCode; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  | use OAuth2\GrantType\UserCredentials; | ||||||
|  | use OAuth2\Scope; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class TokenControllerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testNoGrantType() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->handleTokenRequest(TestRequest::createPost(), $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The grant type was not specified in the request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidGrantType() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'invalid_grant_type', // invalid grant type | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'unsupported_grant_type'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Grant type "invalid_grant_type" not supported'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoClientId() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode', | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Client credentials were not found in the headers or body'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoClientSecretWithConfidentialClient() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode', | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoClientSecretWithEmptySecret() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode-empty-secret', | ||||||
|  |             'client_id' => 'Test Client ID Empty Secret', // valid client id | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidClientId() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode', | ||||||
|  |             'client_id'  => 'Fake Client ID', // invalid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidClientSecret() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode', | ||||||
|  |             'client_id'  => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'Fake Client Secret', // invalid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidTokenResponse() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code' => 'testcode', // valid authorization code | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($response instanceof Response); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |         $this->assertNotNull($response->getParameter('expires_in')); | ||||||
|  |         $this->assertNotNull($response->getParameter('token_type')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidClientIdScope() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode', | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'scope' => 'clientscope1 clientscope2' | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |         $this->assertEquals('clientscope1 clientscope2', $response->getParameter('scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidClientIdScope() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'code'       => 'testcode-with-scope', | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'scope' => 'clientscope3' | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testEnforceScope() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new ClientCredentials($storage)); | ||||||
|  |  | ||||||
|  |         $scope = new Scope(array( | ||||||
|  |             'default_scope' => false, | ||||||
|  |             'supported_scopes' => array('testscope') | ||||||
|  |         )); | ||||||
|  |         $server->setScopeUtil($scope); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id'  => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $response = $server->handleTokenRequest($request); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'This application requires you specify a scope parameter'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCanReceiveAccessTokenUsingPasswordGrantTypeWithoutClientSecret() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new UserCredentials($storage)); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password',                          // valid grant type | ||||||
|  |             'client_id'  => 'Test Client ID For Password Grant', // valid client id | ||||||
|  |             'username'   => 'johndoe',                           // valid username | ||||||
|  |             'password'   => 'password',                          // valid password for username | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($response instanceof Response); | ||||||
|  |         $this->assertEquals(200, $response->getStatusCode(), var_export($response, 1)); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |         $this->assertNotNull($response->getParameter('expires_in')); | ||||||
|  |         $this->assertNotNull($response->getParameter('token_type')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidTokenTypeHintForRevoke() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'token_type_hint' => 'foo', | ||||||
|  |             'token' => 'sometoken' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleRevokeRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($response instanceof Response); | ||||||
|  |         $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1)); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Token type hint must be either \'access_token\' or \'refresh_token\''); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMissingTokenForRevoke() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'token_type_hint' => 'access_token' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleRevokeRequest($request, $response = new Response()); | ||||||
|  |         $this->assertTrue($response instanceof Response); | ||||||
|  |         $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1)); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing token parameter to revoke'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidRequestMethodForRevoke() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = new TestRequest(); | ||||||
|  |         $request->setQuery(array( | ||||||
|  |             'token_type_hint' => 'access_token' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleRevokeRequest($request, $response = new Response()); | ||||||
|  |         $this->assertTrue($response instanceof Response); | ||||||
|  |         $this->assertEquals(405, $response->getStatusCode(), var_export($response, 1)); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The request method must be POST when revoking an access token'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCreateController() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $accessToken = new \OAuth2\ResponseType\AccessToken($storage); | ||||||
|  |         $controller = new TokenController($accessToken, $storage); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Encryption; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  |  | ||||||
|  | class FirebaseJwtTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     private $privateKey; | ||||||
|  |  | ||||||
|  |     public function setUp() | ||||||
|  |     { | ||||||
|  |         $this->privateKey = <<<EOD | ||||||
|  | -----BEGIN RSA PRIVATE KEY----- | ||||||
|  | MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA | ||||||
|  | nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO | ||||||
|  | IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB | ||||||
|  | AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y | ||||||
|  | kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 | ||||||
|  | 3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS | ||||||
|  | R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP | ||||||
|  | l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm | ||||||
|  | zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG | ||||||
|  | PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 | ||||||
|  | QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 | ||||||
|  | niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh | ||||||
|  | suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= | ||||||
|  | -----END RSA PRIVATE KEY----- | ||||||
|  | EOD; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideClientCredentials */ | ||||||
|  |     public function testJwtUtil($client_id, $client_key) | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new FirebaseJwt(); | ||||||
|  |  | ||||||
|  |         $params = array( | ||||||
|  |             'iss' => $client_id, | ||||||
|  |             'exp' => time() + 1000, | ||||||
|  |             'iat' => time(), | ||||||
|  |             'sub' => 'testuser@ourdomain.com', | ||||||
|  |             'aud' => 'http://myapp.com/oauth/auth', | ||||||
|  |             'scope' => null, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256'); | ||||||
|  |  | ||||||
|  |         // test BC behaviour of trusting the algorithm in the header | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |  | ||||||
|  |         // test BC behaviour of not verifying by passing false | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key, false); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |  | ||||||
|  |         // test the new restricted algorithms header | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidJwt() | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new FirebaseJwt(); | ||||||
|  |  | ||||||
|  |         $this->assertFalse($jwtUtil->decode('goob')); | ||||||
|  |         $this->assertFalse($jwtUtil->decode('go.o.b')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideClientCredentials */ | ||||||
|  |     public function testInvalidJwtHeader($client_id, $client_key) | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new FirebaseJwt(); | ||||||
|  |  | ||||||
|  |         $params = array( | ||||||
|  |             'iss' => $client_id, | ||||||
|  |             'exp' => time() + 1000, | ||||||
|  |             'iat' => time(), | ||||||
|  |             'sub' => 'testuser@ourdomain.com', | ||||||
|  |             'aud' => 'http://myapp.com/oauth/auth', | ||||||
|  |             'scope' => null, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // testing for algorithm tampering when only RSA256 signing is allowed | ||||||
|  |         // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ | ||||||
|  |         $tampered = $jwtUtil->encode($params, $client_key, 'HS256'); | ||||||
|  |  | ||||||
|  |         $payload = $jwtUtil->decode($tampered, $client_key, array('RS256')); | ||||||
|  |  | ||||||
|  |         $this->assertFalse($payload); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function provideClientCredentials() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $client_id  = 'Test Client ID'; | ||||||
|  |         $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com"); | ||||||
|  |  | ||||||
|  |         return array( | ||||||
|  |             array($client_id, $client_key), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								library/oauth2/test/OAuth2/Encryption/JwtTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								library/oauth2/test/OAuth2/Encryption/JwtTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Encryption; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  |  | ||||||
|  | class JwtTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     private $privateKey; | ||||||
|  |  | ||||||
|  |     public function setUp() | ||||||
|  |     { | ||||||
|  |         $this->privateKey = <<<EOD | ||||||
|  | -----BEGIN RSA PRIVATE KEY----- | ||||||
|  | MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA | ||||||
|  | nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO | ||||||
|  | IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB | ||||||
|  | AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y | ||||||
|  | kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 | ||||||
|  | 3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS | ||||||
|  | R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP | ||||||
|  | l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm | ||||||
|  | zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG | ||||||
|  | PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 | ||||||
|  | QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 | ||||||
|  | niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh | ||||||
|  | suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= | ||||||
|  | -----END RSA PRIVATE KEY----- | ||||||
|  | EOD; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideClientCredentials */ | ||||||
|  |     public function testJwtUtil($client_id, $client_key) | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new Jwt(); | ||||||
|  |  | ||||||
|  |         $params = array( | ||||||
|  |             'iss' => $client_id, | ||||||
|  |             'exp' => time() + 1000, | ||||||
|  |             'iat' => time(), | ||||||
|  |             'sub' => 'testuser@ourdomain.com', | ||||||
|  |             'aud' => 'http://myapp.com/oauth/auth', | ||||||
|  |             'scope' => null, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256'); | ||||||
|  |  | ||||||
|  |         // test BC behaviour of trusting the algorithm in the header | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |  | ||||||
|  |         // test BC behaviour of not verifying by passing false | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key, false); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |  | ||||||
|  |         // test the new restricted algorithms header | ||||||
|  |         $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); | ||||||
|  |         $this->assertEquals($params, $payload); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidJwt() | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new Jwt(); | ||||||
|  |  | ||||||
|  |         $this->assertFalse($jwtUtil->decode('goob')); | ||||||
|  |         $this->assertFalse($jwtUtil->decode('go.o.b')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideClientCredentials */ | ||||||
|  |     public function testInvalidJwtHeader($client_id, $client_key) | ||||||
|  |     { | ||||||
|  |         $jwtUtil = new Jwt(); | ||||||
|  |  | ||||||
|  |         $params = array( | ||||||
|  |             'iss' => $client_id, | ||||||
|  |             'exp' => time() + 1000, | ||||||
|  |             'iat' => time(), | ||||||
|  |             'sub' => 'testuser@ourdomain.com', | ||||||
|  |             'aud' => 'http://myapp.com/oauth/auth', | ||||||
|  |             'scope' => null, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // testing for algorithm tampering when only RSA256 signing is allowed | ||||||
|  |         // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ | ||||||
|  |         $tampered = $jwtUtil->encode($params, $client_key, 'HS256'); | ||||||
|  |  | ||||||
|  |         $payload = $jwtUtil->decode($tampered, $client_key, array('RS256')); | ||||||
|  |  | ||||||
|  |         $this->assertFalse($payload); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function provideClientCredentials() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $client_id  = 'Test Client ID'; | ||||||
|  |         $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com"); | ||||||
|  |  | ||||||
|  |         return array( | ||||||
|  |             array($client_id, $client_key), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										207
									
								
								library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testNoCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "code" is required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'InvalidCode', // invalid authorization code | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCodeCannotBeUsedTwice() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode', // valid code | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |  | ||||||
|  |         // try to use the same code again | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testExpiredCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-expired', // expired authorization code | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The authorization code has expired'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode', // valid code | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCodeNoScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-with-scope', // valid code | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1 scope2'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCodeSameScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-with-scope', // valid code | ||||||
|  |             'scope'         => 'scope2 scope1', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope2 scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCodeLessScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-with-scope', // valid code | ||||||
|  |             'scope'         => 'scope1', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCodeDifferentScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-with-scope', // valid code | ||||||
|  |             'scope'         => 'scope3', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCodeInvalidScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-with-scope', // valid code | ||||||
|  |             'scope'         => 'invalid-scope', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidClientDifferentCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Some Other Client', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret3', // valid client secret | ||||||
|  |             'code'          => 'testcode', // valid code | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'authorization_code doesn\'t exist or is invalid for the client'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										159
									
								
								library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class ClientCredentialsTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testInvalidCredentials() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'FakeSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentials() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertNull($token['scope']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsWithScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'scope' => 'scope1', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsInvalidScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'scope' => 'invalid-scope', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsInHeader() | ||||||
|  |     { | ||||||
|  |         // create with HTTP_AUTHORIZATION in header | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $headers = array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('Test Client ID:TestSecret'), 'REQUEST_METHOD' => 'POST'); | ||||||
|  |         $params  = array('grant_type' => 'client_credentials'); | ||||||
|  |         $request = new Request(array(), $params, array(), array(), array(), $headers); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertNotNull($token['access_token']); | ||||||
|  |  | ||||||
|  |         // create using PHP Authorization Globals | ||||||
|  |         $headers = array('PHP_AUTH_USER' => 'Test Client ID', 'PHP_AUTH_PW' => 'TestSecret', 'REQUEST_METHOD' => 'POST'); | ||||||
|  |         $params  = array('grant_type' => 'client_credentials'); | ||||||
|  |         $request = new Request(array(), $params, array(), array(), array(), $headers); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertNotNull($token['access_token']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsInRequest() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertNotNull($token['access_token']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsInQuerystring() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'client_credentials', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertNotNull($token['access_token']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testClientUserIdIsSetInAccessToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'client_credentials', // valid grant type | ||||||
|  |             'client_id'     => 'Client ID With User ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |  | ||||||
|  |         // verify the user_id was associated with the token | ||||||
|  |         $storage = $server->getStorage('client'); | ||||||
|  |         $token = $storage->getAccessToken($token['access_token']); | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('user_id', $token); | ||||||
|  |         $this->assertEquals($token['user_id'], 'brent@brentertainment.com'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new ClientCredentials($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								library/oauth2/test/OAuth2/GrantType/ImplicitTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								library/oauth2/test/OAuth2/GrantType/ImplicitTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class ImplicitTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testImplicitNotAllowedResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'token', // invalid response type | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'unsupported_response_type'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'implicit grant type not supported'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUserDeniesAccessResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'token', // valid response type | ||||||
|  |             'state' => 'xyz', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), false); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($query['error'], 'access_denied'); | ||||||
|  |         $this->assertEquals($query['error_description'], 'The user denied access to your application'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulRequestFragmentParameter() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'token', // valid response type | ||||||
|  |             'state' => 'xyz', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri | ||||||
|  |         $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['query'])); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('access_token', $params); | ||||||
|  |         $this->assertArrayHasKey('expires_in', $params); | ||||||
|  |         $this->assertArrayHasKey('token_type', $params); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulRequestReturnsStateParameter() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'token', // valid response type | ||||||
|  |             'state' => 'test', // valid state string (just needs to be passed back to us) | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('state', $params); | ||||||
|  |         $this->assertEquals($params['state'], 'test'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSuccessfulRequestStripsExtraParameters() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri' => 'http://adobe.com?fake=something', // valid redirect URI | ||||||
|  |             'response_type' => 'token', // valid response type | ||||||
|  |             'state' => 'test', // valid state string (just needs to be passed back to us) | ||||||
|  |             'fake' => 'something', // add extra param to querystring | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNull($response->getParameter('error_description')); | ||||||
|  |  | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertFalse(isset($parts['fake'])); | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |  | ||||||
|  |         $this->assertFalse(isset($params['fake'])); | ||||||
|  |         $this->assertArrayHasKey('state', $params); | ||||||
|  |         $this->assertEquals($params['state'], 'test'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         // Add the two types supported for authorization grant | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										360
									
								
								library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,360 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  |  | ||||||
|  | class JwtBearerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     private $privateKey; | ||||||
|  |  | ||||||
|  |     public function setUp() | ||||||
|  |     { | ||||||
|  |         $this->privateKey = <<<EOD | ||||||
|  | -----BEGIN RSA PRIVATE KEY----- | ||||||
|  | MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA | ||||||
|  | nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO | ||||||
|  | IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB | ||||||
|  | AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y | ||||||
|  | kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 | ||||||
|  | 3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS | ||||||
|  | R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP | ||||||
|  | l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm | ||||||
|  | zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG | ||||||
|  | PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 | ||||||
|  | QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 | ||||||
|  | niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh | ||||||
|  | suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= | ||||||
|  | -----END RSA PRIVATE KEY----- | ||||||
|  | EOD; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMalformedJWT() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get the jwt and break it | ||||||
|  |         $jwt = $this->getJWT(); | ||||||
|  |         $jwt = substr_replace($jwt, 'broken', 3, 6); | ||||||
|  |  | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JWT is malformed'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testBrokenSignature() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get the jwt and break signature | ||||||
|  |         $jwt = $this->getJWT() . 'notSupposeToBeHere'; | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JWT failed signature verification'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testExpiredJWT() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get an expired JWT | ||||||
|  |         $jwt = $this->getJWT(1234); | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JWT has expired'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testBadExp() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get an expired JWT | ||||||
|  |         $jwt = $this->getJWT('badtimestamp'); | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Expiration (exp) time must be a unix time stamp'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoAssert() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Do not pass the assert (JWT) | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "assertion" required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNotBefore() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get a future NBF | ||||||
|  |         $jwt = $this->getJWT(null, time() + 10000); | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JWT cannot be used before the Not Before (nbf) time'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testBadNotBefore() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         //Get a non timestamp nbf | ||||||
|  |         $jwt = $this->getJWT(null, 'notatimestamp'); | ||||||
|  |         $request->request['assertion'] = $jwt; | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Not Before (nbf) time must be a unix time stamp'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNonMatchingAudience() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer('http://google.com/oauth/o/auth'); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type | ||||||
|  |             'assertion' => $this->getJWT(), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid audience (aud)'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testBadClientID() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion' => $this->getJWT(null, null, null, 'bad_client_id'), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testBadSubject() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion' => $this->getJWT(null, null, 'anotheruser@ourdomain,com'), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMissingKey() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion' => $this->getJWT(null, null, null, 'Missing Key Cli,nt'), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidJwt() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion' => $this->getJWT(), // valid assertion | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidJwtWithScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion'  => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion | ||||||
|  |             'scope'      => 'scope1', // valid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidJwtInvalidScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |             'assertion'  => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion | ||||||
|  |             'scope'      => 'invalid-scope', // invalid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidJti() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |                 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |                 'assertion' => $this->getJWT(null, null, 'testuser@ourdomain.com', 'Test Client ID', 'unused_jti'), // valid assertion with invalid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidJti() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |                 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |                 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'used_jti'), // valid assertion with invalid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testJtiReplayAttack() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |                 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',  // valid grant type | ||||||
|  |                 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'totally_new_jti'), // valid assertion with invalid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |  | ||||||
|  |         //Replay the same request | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Generates a JWT | ||||||
|  |      * @param $exp The expiration date. If the current time is greater than the exp, the JWT is invalid. | ||||||
|  |      * @param $nbf The "not before" time. If the current time is less than the nbf, the JWT is invalid. | ||||||
|  |      * @param $sub The subject we are acting on behalf of. This could be the email address of the user in the system. | ||||||
|  |      * @param $iss The issuer, usually the client_id. | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     private function getJWT($exp = null, $nbf = null, $sub = null, $iss = 'Test Client ID', $jti = null) | ||||||
|  |     { | ||||||
|  |         if (!$exp) { | ||||||
|  |             $exp = time() + 1000; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$sub) { | ||||||
|  |             $sub = "testuser@ourdomain.com"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $params = array( | ||||||
|  |             'iss' => $iss, | ||||||
|  |             'exp' => $exp, | ||||||
|  |             'iat' => time(), | ||||||
|  |             'sub' => $sub, | ||||||
|  |             'aud' => 'http://myapp.com/oauth/auth', | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if ($nbf) { | ||||||
|  |             $params['nbf'] = $nbf; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($jti) { | ||||||
|  |             $params['jti'] = $jti; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $jwtUtil = new Jwt(); | ||||||
|  |  | ||||||
|  |         return $jwtUtil->encode($params, $this->privateKey, 'RS256'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($audience = 'http://myapp.com/oauth/auth') | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new JwtBearer($storage, $audience, new Jwt())); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										204
									
								
								library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class RefreshTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     private $storage; | ||||||
|  |  | ||||||
|  |     public function testNoRefreshToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->addGrantType(new RefreshToken($this->storage)); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token',  // valid grant type | ||||||
|  |             'client_id'  => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',  // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "refresh_token" is required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidRefreshToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->addGrantType(new RefreshToken($this->storage)); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'fake-token', // invalid refresh token | ||||||
|  |         )); | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid refresh token'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenWithNewRefreshTokenInResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => true))); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken', // valid refresh token | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |         $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); | ||||||
|  |  | ||||||
|  |         $refresh_token = $this->storage->getRefreshToken($token['refresh_token']); | ||||||
|  |         $this->assertNotNull($refresh_token); | ||||||
|  |         $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']); | ||||||
|  |         $this->assertEquals($refresh_token['client_id'], $request->request('client_id')); | ||||||
|  |         $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used'); | ||||||
|  |         $used_token = $this->storage->getRefreshToken('test-refreshtoken'); | ||||||
|  |         $this->assertFalse($used_token, 'the refresh token used is no longer valid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenDoesNotUnsetToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->addGrantType(new RefreshToken($this->storage, array( | ||||||
|  |             'always_issue_new_refresh_token' => true, | ||||||
|  |             'unset_refresh_token_after_use'  => false, | ||||||
|  |         ))); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken', // valid refresh token | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |         $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); | ||||||
|  |  | ||||||
|  |         $used_token = $this->storage->getRefreshToken('test-refreshtoken'); | ||||||
|  |         $this->assertNotNull($used_token, 'the refresh token used is still valid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenWithNoRefreshTokenInResponse() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => false))); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken', // valid refresh token | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |         $this->assertFalse(isset($token['refresh_token']), 'refresh token should not be returned'); | ||||||
|  |  | ||||||
|  |         $used_token = $this->storage->getRefreshToken('test-refreshtoken'); | ||||||
|  |         $this->assertNotNull($used_token, 'the refresh token used is still valid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenSameScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) | ||||||
|  |             'scope'         => 'scope2 scope1', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope2 scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenLessScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) | ||||||
|  |             'scope'         => 'scope1', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenDifferentScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) | ||||||
|  |             'scope'         => 'scope3', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidRefreshTokenInvalidScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) | ||||||
|  |             'scope'         => 'invalid-scope', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidClientDifferentRefreshToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'refresh_token', // valid grant type | ||||||
|  |             'client_id'     => 'Test Some Other Client', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret3', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken', // valid refresh token | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'refresh_token doesn\'t exist or is invalid for the client'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $this->storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($this->storage); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										172
									
								
								library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class UserCredentialsTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testNoUsername() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |         )); | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoPassword() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |         )); | ||||||
|  |         $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_request'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidUsername() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'fake-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testInvalidPassword() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'fakepass', // invalid password | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 401); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_grant'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentials() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsWithScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |             'scope'    => 'scope1', // valid scope | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('scope', $token); | ||||||
|  |         $this->assertEquals($token['scope'], 'scope1'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidCredentialsInvalidScope() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |             'scope'         => 'invalid-scope', | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_scope'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoSecretWithPublicClient() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID Empty Secret', // valid public client | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNoSecretWithConfidentialClient() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'password', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid public client | ||||||
|  |             'username' => 'test-username', // valid username | ||||||
|  |             'password' => 'testpass', // valid password | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $token = $server->grantAccessToken($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 400); | ||||||
|  |         $this->assertEquals($response->getParameter('error'), 'invalid_client'); | ||||||
|  |         $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new UserCredentials($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,182 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testValidateAuthorizeRequest() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $response = new Response(); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'state'         => 'af0ifjsldkj', | ||||||
|  |             'nonce'         => 'n-0S6_WzA2Mj', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // Test valid id_token request | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['fragment'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); | ||||||
|  |         $this->assertEquals($query['state'], 'af0ifjsldkj'); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('id_token', $query); | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertArrayNotHasKey('access_token', $query); | ||||||
|  |         $this->assertArrayNotHasKey('expires_in', $query); | ||||||
|  |         $this->assertArrayNotHasKey('token_type', $query); | ||||||
|  |  | ||||||
|  |         // Test valid token id_token request | ||||||
|  |         $request->query['response_type'] = 'id_token token'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['fragment'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); | ||||||
|  |         $this->assertEquals($query['state'], 'af0ifjsldkj'); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('access_token', $query); | ||||||
|  |         $this->assertArrayHasKey('expires_in', $query); | ||||||
|  |         $this->assertArrayHasKey('token_type', $query); | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertArrayHasKey('id_token', $query); | ||||||
|  |  | ||||||
|  |         // assert that with multiple-valued response types, order does not matter | ||||||
|  |         $request->query['response_type'] = 'token id_token'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['fragment'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); | ||||||
|  |         $this->assertEquals($query['state'], 'af0ifjsldkj'); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('access_token', $query); | ||||||
|  |         $this->assertArrayHasKey('expires_in', $query); | ||||||
|  |         $this->assertArrayHasKey('token_type', $query); | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertArrayHasKey('id_token', $query); | ||||||
|  |  | ||||||
|  |         // assert that with multiple-valued response types with extra spaces do not matter | ||||||
|  |         $request->query['response_type'] = ' token  id_token '; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['fragment'], $query); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); | ||||||
|  |         $this->assertEquals($query['state'], 'af0ifjsldkj'); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('access_token', $query); | ||||||
|  |         $this->assertArrayHasKey('expires_in', $query); | ||||||
|  |         $this->assertArrayHasKey('token_type', $query); | ||||||
|  |         $this->assertArrayHasKey('state', $query); | ||||||
|  |         $this->assertArrayHasKey('id_token', $query); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMissingNonce() | ||||||
|  |     { | ||||||
|  |         $server    = $this->getTestServer(); | ||||||
|  |         $authorize = $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $response = new Response(); | ||||||
|  |         $request  = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'state'         => 'xyz', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // Test missing nonce for 'id_token' response type | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |         $params = $response->getParameters(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($params['error'], 'invalid_nonce'); | ||||||
|  |         $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter'); | ||||||
|  |  | ||||||
|  |         // Test missing nonce for 'id_token token' response type | ||||||
|  |         $request->query['response_type'] = 'id_token token'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, true); | ||||||
|  |         $params = $response->getParameters(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($params['error'], 'invalid_nonce'); | ||||||
|  |         $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNotGrantedApplication() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $response = new Response(); | ||||||
|  |         $request  = new Request(array( | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', // valid redirect URI | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'state'         => 'af0ifjsldkj', | ||||||
|  |             'nonce'         => 'n-0S6_WzA2Mj', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // Test not approved application | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, false); | ||||||
|  |  | ||||||
|  |         $params = $response->getParameters(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($params['error'], 'consent_required'); | ||||||
|  |         $this->assertEquals($params['error_description'], 'The user denied access to your application'); | ||||||
|  |  | ||||||
|  |         // Test not approved application with prompt parameter | ||||||
|  |         $request->query['prompt'] = 'none'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, false); | ||||||
|  |  | ||||||
|  |         $params = $response->getParameters(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($params['error'], 'login_required'); | ||||||
|  |         $this->assertEquals($params['error_description'], 'The user must log in'); | ||||||
|  |  | ||||||
|  |         // Test not approved application with user_id set | ||||||
|  |         $request->query['prompt'] = 'none'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response, false, 'some-user-id'); | ||||||
|  |  | ||||||
|  |         $params = $response->getParameters(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($params['error'], 'interaction_required'); | ||||||
|  |         $this->assertEquals($params['error_description'], 'The user must grant access to your application'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNeedsIdToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $authorize = $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($authorize->needsIdToken('openid')); | ||||||
|  |         $this->assertTrue($authorize->needsIdToken('openid profile')); | ||||||
|  |         $this->assertFalse($authorize->needsIdToken('')); | ||||||
|  |         $this->assertFalse($authorize->needsIdToken('some-scope')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $config += array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer'             => 'phpunit', | ||||||
|  |             'allow_implicit'     => true | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server  = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Controller; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class UserInfoControllerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testCreateController() | ||||||
|  |     { | ||||||
|  |         $tokenType = new \OAuth2\TokenType\Bearer(); | ||||||
|  |         $storage = new \OAuth2\Storage\Memory(); | ||||||
|  |         $controller = new UserInfoController($tokenType, $storage, $storage); | ||||||
|  |  | ||||||
|  |         $response = new Response(); | ||||||
|  |         $controller->handleUserInfoRequest(new Request(), $response); | ||||||
|  |         $this->assertEquals(401, $response->getStatusCode()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testValidToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = Request::createFromGlobals(); | ||||||
|  |         $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-openid-connect'; | ||||||
|  |         $response = new Response(); | ||||||
|  |  | ||||||
|  |         $server->handleUserInfoRequest($request, $response); | ||||||
|  |         $parameters = $response->getParameters(); | ||||||
|  |         $this->assertEquals($parameters['sub'], 'testuser'); | ||||||
|  |         $this->assertEquals($parameters['email'], 'testuser@test.com'); | ||||||
|  |         $this->assertEquals($parameters['email_verified'], true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,57 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\GrantType; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Response; | ||||||
|  |  | ||||||
|  | class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testValidCode() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-openid', // valid code | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('id_token', $token); | ||||||
|  |         $this->assertEquals('test_id_token', $token['id_token']); | ||||||
|  |  | ||||||
|  |         // this is only true if "offline_access" was requested | ||||||
|  |         $this->assertFalse(isset($token['refresh_token'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testOfflineAccess() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'authorization_code', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'code'          => 'testcode-openid', // valid code | ||||||
|  |             'scope'         => 'offline_access', // valid code | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('id_token', $token); | ||||||
|  |         $this->assertEquals('test_id_token', $token['id_token']); | ||||||
|  |         $this->assertTrue(isset($token['refresh_token'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, array('use_openid_connect' => true)); | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,182 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  |  | ||||||
|  | class CodeIdTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testHandleAuthorizeRequest() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'code id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['query'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayHasKey('code', $params); | ||||||
|  |  | ||||||
|  |         // validate ID Token | ||||||
|  |         $parts = explode('.', $params['id_token']); | ||||||
|  |         foreach ($parts as &$part) { | ||||||
|  |             // Each part is a base64url encoded json string. | ||||||
|  |             $part = str_replace(array('-', '_'), array('+', '/'), $part); | ||||||
|  |             $part = base64_decode($part); | ||||||
|  |             $part = json_decode($part, true); | ||||||
|  |         } | ||||||
|  |         list($header, $claims, $signature) = $parts; | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('iss', $claims); | ||||||
|  |         $this->assertArrayHasKey('sub', $claims); | ||||||
|  |         $this->assertArrayHasKey('aud', $claims); | ||||||
|  |         $this->assertArrayHasKey('iat', $claims); | ||||||
|  |         $this->assertArrayHasKey('exp', $claims); | ||||||
|  |         $this->assertArrayHasKey('auth_time', $claims); | ||||||
|  |         $this->assertArrayHasKey('nonce', $claims); | ||||||
|  |  | ||||||
|  |         // only exists if an access token was granted along with the id_token | ||||||
|  |         $this->assertArrayNotHasKey('at_hash', $claims); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($claims['iss'], 'test'); | ||||||
|  |         $this->assertEquals($claims['aud'], 'Test Client ID'); | ||||||
|  |         $this->assertEquals($claims['nonce'], 'test'); | ||||||
|  |         $duration = $claims['exp'] - $claims['iat']; | ||||||
|  |         $this->assertEquals($duration, 3600); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUserClaimsWithUserId() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'code id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid email', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $userId = 'testuser'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['query'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayHasKey('code', $params); | ||||||
|  |  | ||||||
|  |         // validate ID Token | ||||||
|  |         $parts = explode('.', $params['id_token']); | ||||||
|  |         foreach ($parts as &$part) { | ||||||
|  |             // Each part is a base64url encoded json string. | ||||||
|  |             $part = str_replace(array('-', '_'), array('+', '/'), $part); | ||||||
|  |             $part = base64_decode($part); | ||||||
|  |             $part = json_decode($part, true); | ||||||
|  |         } | ||||||
|  |         list($header, $claims, $signature) = $parts; | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('email', $claims); | ||||||
|  |         $this->assertArrayHasKey('email_verified', $claims); | ||||||
|  |         $this->assertNotNull($claims['email']); | ||||||
|  |         $this->assertNotNull($claims['email_verified']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUserClaimsWithoutUserId() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'code id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid email', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $userId = null; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('query', $parts); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['query'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayHasKey('code', $params); | ||||||
|  |  | ||||||
|  |         // validate ID Token | ||||||
|  |         $parts = explode('.', $params['id_token']); | ||||||
|  |         foreach ($parts as &$part) { | ||||||
|  |             // Each part is a base64url encoded json string. | ||||||
|  |             $part = str_replace(array('-', '_'), array('+', '/'), $part); | ||||||
|  |             $part = base64_decode($part); | ||||||
|  |             $part = json_decode($part, true); | ||||||
|  |         } | ||||||
|  |         list($header, $claims, $signature) = $parts; | ||||||
|  |  | ||||||
|  |         $this->assertArrayNotHasKey('email', $claims); | ||||||
|  |         $this->assertArrayNotHasKey('email_verified', $claims); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $config += array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'test', | ||||||
|  |             'id_lifetime' => 3600, | ||||||
|  |             'allow_implicit' => true, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $memoryStorage->supportedScopes[] = 'email'; | ||||||
|  |         $responseTypes = array( | ||||||
|  |             'code'     => $code    = new AuthorizationCode($memoryStorage), | ||||||
|  |             'id_token' => $idToken = new IdToken($memoryStorage, $memoryStorage, $config), | ||||||
|  |             'code id_token' => new CodeIdToken($code, $idToken), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $server = new Server($memoryStorage, $config, array(), $responseTypes); | ||||||
|  |         $server->addGrantType(new ClientCredentials($memoryStorage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										184
									
								
								library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  |  | ||||||
|  | class IdTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testValidateAuthorizeRequest() | ||||||
|  |     { | ||||||
|  |         $query = array( | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid', | ||||||
|  |             'state'         => 'test', | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // attempt to do the request without a nonce. | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request($query); | ||||||
|  |         $valid = $server->validateAuthorizeRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         // Add a nonce and retry. | ||||||
|  |         $query['nonce'] = 'test'; | ||||||
|  |         $request = new Request($query); | ||||||
|  |         $valid = $server->validateAuthorizeRequest($request, $response = new Response()); | ||||||
|  |         $this->assertTrue($valid); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHandleAuthorizeRequest() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid email', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $user_id = 'testuser'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['query'])); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayNotHasKey('access_token', $params); | ||||||
|  |         $this->validateIdToken($params['id_token']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testPassInAuthTime() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'id_token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid email', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // test with a scalar user id | ||||||
|  |         $user_id = 'testuser123'; | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id); | ||||||
|  |  | ||||||
|  |         list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response); | ||||||
|  |  | ||||||
|  |         $this->assertTrue(is_array($payload)); | ||||||
|  |         $this->assertArrayHasKey('sub', $payload); | ||||||
|  |         $this->assertEquals($user_id, $payload['sub']); | ||||||
|  |         $this->assertArrayHasKey('auth_time', $payload); | ||||||
|  |  | ||||||
|  |         // test with an array of user info | ||||||
|  |         $userInfo = array( | ||||||
|  |             'user_id' => 'testuser1234', | ||||||
|  |             'auth_time' => date('Y-m-d H:i:s', strtotime('20 minutes ago') | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true, $userInfo); | ||||||
|  |  | ||||||
|  |         list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response); | ||||||
|  |  | ||||||
|  |         $this->assertTrue(is_array($payload)); | ||||||
|  |         $this->assertArrayHasKey('sub', $payload); | ||||||
|  |         $this->assertEquals($userInfo['user_id'], $payload['sub']); | ||||||
|  |         $this->assertArrayHasKey('auth_time', $payload); | ||||||
|  |         $this->assertEquals($userInfo['auth_time'], $payload['auth_time']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function extractTokenDataFromResponse(Response $response) | ||||||
|  |     { | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['query'])); | ||||||
|  |  | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayNotHasKey('access_token', $params); | ||||||
|  |  | ||||||
|  |         list($headb64, $payloadb64, $signature) = explode('.', $params['id_token']); | ||||||
|  |  | ||||||
|  |         $jwt = new Jwt(); | ||||||
|  |         $header = json_decode($jwt->urlSafeB64Decode($headb64), true); | ||||||
|  |         $payload = json_decode($jwt->urlSafeB64Decode($payloadb64), true); | ||||||
|  |  | ||||||
|  |         return array($header, $payload, $signature); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function validateIdToken($id_token) | ||||||
|  |     { | ||||||
|  |         $parts = explode('.', $id_token); | ||||||
|  |         foreach ($parts as &$part) { | ||||||
|  |             // Each part is a base64url encoded json string. | ||||||
|  |             $part = str_replace(array('-', '_'), array('+', '/'), $part); | ||||||
|  |             $part = base64_decode($part); | ||||||
|  |             $part = json_decode($part, true); | ||||||
|  |         } | ||||||
|  |         list($header, $claims, $signature) = $parts; | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('iss', $claims); | ||||||
|  |         $this->assertArrayHasKey('sub', $claims); | ||||||
|  |         $this->assertArrayHasKey('aud', $claims); | ||||||
|  |         $this->assertArrayHasKey('iat', $claims); | ||||||
|  |         $this->assertArrayHasKey('exp', $claims); | ||||||
|  |         $this->assertArrayHasKey('auth_time', $claims); | ||||||
|  |         $this->assertArrayHasKey('nonce', $claims); | ||||||
|  |         $this->assertArrayHasKey('email', $claims); | ||||||
|  |         $this->assertArrayHasKey('email_verified', $claims); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($claims['iss'], 'test'); | ||||||
|  |         $this->assertEquals($claims['aud'], 'Test Client ID'); | ||||||
|  |         $this->assertEquals($claims['nonce'], 'test'); | ||||||
|  |         $this->assertEquals($claims['email'], 'testuser@test.com'); | ||||||
|  |         $duration = $claims['exp'] - $claims['iat']; | ||||||
|  |         $this->assertEquals($duration, 3600); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $config += array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'test', | ||||||
|  |             'id_lifetime' => 3600, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $memoryStorage->supportedScopes[] = 'email'; | ||||||
|  |         $storage = array( | ||||||
|  |             'client' => $memoryStorage, | ||||||
|  |             'scope' => $memoryStorage, | ||||||
|  |         ); | ||||||
|  |         $responseTypes = array( | ||||||
|  |             'id_token' => new IdToken($memoryStorage, $memoryStorage, $config), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $server = new Server($storage, $config, array(), $responseTypes); | ||||||
|  |         $server->addGrantType(new ClientCredentials($memoryStorage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,91 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Request; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  | use OAuth2\ResponseType\AccessToken; | ||||||
|  |  | ||||||
|  | class IdTokenTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     public function testHandleAuthorizeRequest() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(array('allow_implicit' => true)); | ||||||
|  |  | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'id_token token', | ||||||
|  |             'redirect_uri'  => 'http://adobe.com', | ||||||
|  |             'client_id'     => 'Test Client ID', | ||||||
|  |             'scope'         => 'openid', | ||||||
|  |             'state'         => 'test', | ||||||
|  |             'nonce'         => 'test', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $location = $response->getHttpHeader('Location'); | ||||||
|  |         $this->assertNotContains('error', $location); | ||||||
|  |  | ||||||
|  |         $parts = parse_url($location); | ||||||
|  |         $this->assertArrayHasKey('fragment', $parts); | ||||||
|  |         $this->assertFalse(isset($parts['query'])); | ||||||
|  |  | ||||||
|  |         // assert fragment is in "application/x-www-form-urlencoded" format | ||||||
|  |         parse_str($parts['fragment'], $params); | ||||||
|  |         $this->assertNotNull($params); | ||||||
|  |         $this->assertArrayHasKey('id_token', $params); | ||||||
|  |         $this->assertArrayHasKey('access_token', $params); | ||||||
|  |  | ||||||
|  |         // validate ID Token | ||||||
|  |         $parts = explode('.', $params['id_token']); | ||||||
|  |         foreach ($parts as &$part) { | ||||||
|  |             // Each part is a base64url encoded json string. | ||||||
|  |             $part = str_replace(array('-', '_'), array('+', '/'), $part); | ||||||
|  |             $part = base64_decode($part); | ||||||
|  |             $part = json_decode($part, true); | ||||||
|  |         } | ||||||
|  |         list($header, $claims, $signature) = $parts; | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('iss', $claims); | ||||||
|  |         $this->assertArrayHasKey('sub', $claims); | ||||||
|  |         $this->assertArrayHasKey('aud', $claims); | ||||||
|  |         $this->assertArrayHasKey('iat', $claims); | ||||||
|  |         $this->assertArrayHasKey('exp', $claims); | ||||||
|  |         $this->assertArrayHasKey('auth_time', $claims); | ||||||
|  |         $this->assertArrayHasKey('nonce', $claims); | ||||||
|  |         $this->assertArrayHasKey('at_hash', $claims); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($claims['iss'], 'test'); | ||||||
|  |         $this->assertEquals($claims['aud'], 'Test Client ID'); | ||||||
|  |         $this->assertEquals($claims['nonce'], 'test'); | ||||||
|  |         $duration = $claims['exp'] - $claims['iat']; | ||||||
|  |         $this->assertEquals($duration, 3600); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $config += array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'test', | ||||||
|  |             'id_lifetime' => 3600, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $responseTypes = array( | ||||||
|  |             'token'     => $token   = new AccessToken($memoryStorage, $memoryStorage), | ||||||
|  |             'id_token'  => $idToken = new IdToken($memoryStorage, $memoryStorage, $config), | ||||||
|  |             'id_token token' => new IdTokenToken($token, $idToken), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $server = new Server($memoryStorage, $config, array(), $responseTypes); | ||||||
|  |         $server->addGrantType(new ClientCredentials($memoryStorage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,95 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\BaseTest; | ||||||
|  | use OAuth2\Storage\NullStorage; | ||||||
|  |  | ||||||
|  | class AuthorizationCodeTest extends BaseTest | ||||||
|  | { | ||||||
|  |     /** @dataProvider provideStorage */ | ||||||
|  |     public function testCreateAuthorizationCode($storage) | ||||||
|  |     { | ||||||
|  |         if ($storage instanceof NullStorage) { | ||||||
|  |             $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$storage instanceof AuthorizationCodeInterface) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // assert code we are about to add does not exist | ||||||
|  |         $code = $storage->getAuthorizationCode('new-openid-code'); | ||||||
|  |         $this->assertFalse($code); | ||||||
|  |  | ||||||
|  |         // add new code | ||||||
|  |         $expires = time() + 20; | ||||||
|  |         $scope = null; | ||||||
|  |         $id_token = 'fake_id_token'; | ||||||
|  |         $success = $storage->setAuthorizationCode('new-openid-code', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         $code = $storage->getAuthorizationCode('new-openid-code'); | ||||||
|  |         $this->assertNotNull($code); | ||||||
|  |         $this->assertArrayHasKey('authorization_code', $code); | ||||||
|  |         $this->assertArrayHasKey('client_id', $code); | ||||||
|  |         $this->assertArrayHasKey('user_id', $code); | ||||||
|  |         $this->assertArrayHasKey('redirect_uri', $code); | ||||||
|  |         $this->assertArrayHasKey('expires', $code); | ||||||
|  |         $this->assertEquals($code['authorization_code'], 'new-openid-code'); | ||||||
|  |         $this->assertEquals($code['client_id'], 'client ID'); | ||||||
|  |         $this->assertEquals($code['user_id'], 'SOMEUSERID'); | ||||||
|  |         $this->assertEquals($code['redirect_uri'], 'http://example.com'); | ||||||
|  |         $this->assertEquals($code['expires'], $expires); | ||||||
|  |         $this->assertEquals($code['id_token'], $id_token); | ||||||
|  |  | ||||||
|  |         // change existing code | ||||||
|  |         $expires = time() + 42; | ||||||
|  |         $new_id_token = 'fake_id_token-2'; | ||||||
|  |         $success = $storage->setAuthorizationCode('new-openid-code', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires, $scope, $new_id_token); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         $code = $storage->getAuthorizationCode('new-openid-code'); | ||||||
|  |         $this->assertNotNull($code); | ||||||
|  |         $this->assertArrayHasKey('authorization_code', $code); | ||||||
|  |         $this->assertArrayHasKey('client_id', $code); | ||||||
|  |         $this->assertArrayHasKey('user_id', $code); | ||||||
|  |         $this->assertArrayHasKey('redirect_uri', $code); | ||||||
|  |         $this->assertArrayHasKey('expires', $code); | ||||||
|  |         $this->assertEquals($code['authorization_code'], 'new-openid-code'); | ||||||
|  |         $this->assertEquals($code['client_id'], 'client ID2'); | ||||||
|  |         $this->assertEquals($code['user_id'], 'SOMEOTHERID'); | ||||||
|  |         $this->assertEquals($code['redirect_uri'], 'http://example.org'); | ||||||
|  |         $this->assertEquals($code['expires'], $expires); | ||||||
|  |         $this->assertEquals($code['id_token'], $new_id_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |         /** @dataProvider provideStorage */ | ||||||
|  |     public function testRemoveIdTokenFromAuthorizationCode($storage) | ||||||
|  |     { | ||||||
|  |         // add new code | ||||||
|  |         $expires = time() + 20; | ||||||
|  |         $scope = null; | ||||||
|  |         $id_token = 'fake_id_token_to_remove'; | ||||||
|  |         $authcode = 'new-openid-code-'.rand(); | ||||||
|  |         $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         // verify params were set | ||||||
|  |         $code = $storage->getAuthorizationCode($authcode); | ||||||
|  |         $this->assertNotNull($code); | ||||||
|  |         $this->assertArrayHasKey('id_token', $code); | ||||||
|  |         $this->assertEquals($code['id_token'], $id_token); | ||||||
|  |  | ||||||
|  |         // remove the id_token | ||||||
|  |         $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, null); | ||||||
|  |  | ||||||
|  |         // verify the "id_token" is now null | ||||||
|  |         $code = $storage->getAuthorizationCode($authcode); | ||||||
|  |         $this->assertNotNull($code); | ||||||
|  |         $this->assertArrayHasKey('id_token', $code); | ||||||
|  |         $this->assertEquals($code['id_token'], null); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\OpenID\Storage; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\BaseTest; | ||||||
|  | use OAuth2\Storage\NullStorage; | ||||||
|  |  | ||||||
|  | class UserClaimsTest extends BaseTest | ||||||
|  | { | ||||||
|  |     /** @dataProvider provideStorage */ | ||||||
|  |     public function testGetUserClaims($storage) | ||||||
|  |     { | ||||||
|  |         if ($storage instanceof NullStorage) { | ||||||
|  |             $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$storage instanceof UserClaimsInterface) { | ||||||
|  |             // incompatible storage | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // invalid user | ||||||
|  |         $claims = $storage->getUserClaims('fake-user', ''); | ||||||
|  |         $this->assertFalse($claims); | ||||||
|  |  | ||||||
|  |         // valid user (no scope) | ||||||
|  |         $claims = $storage->getUserClaims('testuser', ''); | ||||||
|  |  | ||||||
|  |         /* assert the decoded token is the same */ | ||||||
|  |         $this->assertFalse(isset($claims['email'])); | ||||||
|  |  | ||||||
|  |         // valid user | ||||||
|  |         $claims = $storage->getUserClaims('testuser', 'email'); | ||||||
|  |  | ||||||
|  |         /* assert the decoded token is the same */ | ||||||
|  |         $this->assertEquals($claims['email'], "testuser@test.com"); | ||||||
|  |         $this->assertEquals($claims['email_verified'], true); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										98
									
								
								library/oauth2/test/OAuth2/RequestTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								library/oauth2/test/OAuth2/RequestTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\GrantType\AuthorizationCode; | ||||||
|  |  | ||||||
|  | class RequestTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testRequestOverride() | ||||||
|  |     { | ||||||
|  |         $request = new TestRequest(); | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         // Smoke test for override request class | ||||||
|  |         // $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         // $this->assertInstanceOf('Response', $response); | ||||||
|  |         // $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |         // $this->assertInstanceOf('Response', $response); | ||||||
|  |         // $response = $server->verifyResourceRequest($request, $response = new Response()); | ||||||
|  |         // $this->assertTrue(is_bool($response)); | ||||||
|  |  | ||||||
|  |         /*** make some valid requests ***/ | ||||||
|  |  | ||||||
|  |         // Valid Token Request | ||||||
|  |         $request->setPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', | ||||||
|  |             'client_id'  => 'Test Client ID', | ||||||
|  |             'client_secret' => 'TestSecret', | ||||||
|  |             'code' => 'testcode', | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 200); | ||||||
|  |         $this->assertNull($response->getParameter('error')); | ||||||
|  |         $this->assertNotNUll($response->getParameter('access_token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHeadersReturnsValueByKey() | ||||||
|  |     { | ||||||
|  |         $request = new Request( | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array('AUTHORIZATION' => 'Basic secret') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('Basic secret', $request->headers('AUTHORIZATION')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHeadersReturnsDefaultIfHeaderNotPresent() | ||||||
|  |     { | ||||||
|  |         $request = new Request(); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('Bearer', $request->headers('AUTHORIZATION', 'Bearer')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHeadersIsCaseInsensitive() | ||||||
|  |     { | ||||||
|  |         $request = new Request( | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array(), | ||||||
|  |             array('AUTHORIZATION' => 'Basic secret') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('Basic secret', $request->headers('Authorization')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRequestReturnsPostParamIfNoQueryParamAvailable() | ||||||
|  |     { | ||||||
|  |         $request = new Request( | ||||||
|  |             array(), | ||||||
|  |             array('client_id' => 'correct') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('correct', $request->query('client_id', $request->request('client_id'))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer($config = array()) | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, $config); | ||||||
|  |  | ||||||
|  |         // Add the two types supported for authorization grant | ||||||
|  |         $server->addGrantType(new AuthorizationCode($storage)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								library/oauth2/test/OAuth2/ResponseTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								library/oauth2/test/OAuth2/ResponseTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | class ResponseTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testRenderAsXml() | ||||||
|  |     { | ||||||
|  |         $response = new Response(array( | ||||||
|  |             'foo' => 'bar', | ||||||
|  |             'halland' => 'oates', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $string = $response->getResponseBody('xml'); | ||||||
|  |         $this->assertContains('<response><foo>bar</foo><halland>oates</halland></response>', $string); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										107
									
								
								library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Storage\Memory; | ||||||
|  |  | ||||||
|  | class AccessTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testRevokeAccessTokenWithTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'access_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken($tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke', 'access_token'); | ||||||
|  |         $this->assertFalse($tokenStorage->getAccessToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeAccessTokenWithoutTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'access_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken($tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke'); | ||||||
|  |         $this->assertFalse($tokenStorage->getAccessToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeRefreshTokenWithTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'refresh_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken(new Memory, $tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke', 'refresh_token'); | ||||||
|  |         $this->assertFalse($tokenStorage->getRefreshToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeRefreshTokenWithoutTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'refresh_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken(new Memory, $tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke'); | ||||||
|  |         $this->assertFalse($tokenStorage->getRefreshToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeAccessTokenWithRefreshTokenTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'access_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken($tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke', 'refresh_token'); | ||||||
|  |         $this->assertFalse($tokenStorage->getAccessToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeAccessTokenWithBogusTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'access_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken($tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke', 'foo'); | ||||||
|  |         $this->assertFalse($tokenStorage->getAccessToken('revoke')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRevokeRefreshTokenWithBogusTypeHint() | ||||||
|  |     { | ||||||
|  |         $tokenStorage = new Memory(array( | ||||||
|  |             'refresh_tokens' => array( | ||||||
|  |                 'revoke' => array('mytoken'), | ||||||
|  |             ), | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); | ||||||
|  |         $accessToken = new AccessToken(new Memory, $tokenStorage); | ||||||
|  |         $accessToken->revokeToken('revoke', 'foo'); | ||||||
|  |         $this->assertFalse($tokenStorage->getRefreshToken('revoke')); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										160
									
								
								library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\ResponseType; | ||||||
|  |  | ||||||
|  | use OAuth2\Server; | ||||||
|  | use OAuth2\Response; | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  | use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage; | ||||||
|  | use OAuth2\GrantType\ClientCredentials; | ||||||
|  | use OAuth2\GrantType\UserCredentials; | ||||||
|  | use OAuth2\GrantType\RefreshToken; | ||||||
|  | use OAuth2\Encryption\Jwt; | ||||||
|  |  | ||||||
|  | class JwtAccessTokenTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testCreateAccessToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $jwtResponseType = $server->getResponseType('token'); | ||||||
|  |  | ||||||
|  |         $accessToken = $jwtResponseType->createAccessToken('Test Client ID', 123, 'test', false); | ||||||
|  |         $jwt = new Jwt; | ||||||
|  |         $decodedAccessToken = $jwt->decode($accessToken['access_token'], null, false); | ||||||
|  |  | ||||||
|  |         $this->assertArrayHasKey('id', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('jti', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('iss', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('aud', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('exp', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('iat', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('token_type', $decodedAccessToken); | ||||||
|  |         $this->assertArrayHasKey('scope', $decodedAccessToken); | ||||||
|  |  | ||||||
|  |         $this->assertEquals('https://api.example.com', $decodedAccessToken['iss']); | ||||||
|  |         $this->assertEquals('Test Client ID', $decodedAccessToken['aud']); | ||||||
|  |         $this->assertEquals(123, $decodedAccessToken['sub']); | ||||||
|  |         $delta = $decodedAccessToken['exp'] - $decodedAccessToken['iat']; | ||||||
|  |         $this->assertEquals(3600, $delta); | ||||||
|  |         $this->assertEquals($decodedAccessToken['id'], $decodedAccessToken['jti']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGrantJwtAccessToken() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'client_credentials', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID',     // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',         // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |         $this->assertEquals(2, substr_count($response->getParameter('access_token'), '.')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAccessResourceWithJwtAccessToken() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'client_credentials', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID',     // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',         // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); | ||||||
|  |  | ||||||
|  |         // make a call to the resource server using the crypto token | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'access_token' => $JwtAccessToken, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($server->verifyResourceRequest($request)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAccessResourceWithJwtAccessTokenUsingSecondaryStorage() | ||||||
|  |     { | ||||||
|  |         // add the test parameters in memory | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'client_credentials', // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID',     // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',         // valid client secret | ||||||
|  |         )); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); | ||||||
|  |  | ||||||
|  |         // make a call to the resource server using the crypto token | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'access_token' => $JwtAccessToken, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // create a resource server with the "memory" storage from the grant server | ||||||
|  |         $resourceServer = new Server($server->getStorage('client_credentials')); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($resourceServer->verifyResourceRequest($request)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testJwtAccessTokenWithRefreshToken() | ||||||
|  |     { | ||||||
|  |         $server = $this->getTestServer(); | ||||||
|  |  | ||||||
|  |         // add "UserCredentials" grant type and "JwtAccessToken" response type | ||||||
|  |         // and ensure "JwtAccessToken" response type has "RefreshToken" storage | ||||||
|  |         $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server->addGrantType(new UserCredentials($memoryStorage)); | ||||||
|  |         $server->addGrantType(new RefreshToken($memoryStorage)); | ||||||
|  |         $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, $memoryStorage), 'token'); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'password',         // valid grant type | ||||||
|  |             'client_id'     => 'Test Client ID',   // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',       // valid client secret | ||||||
|  |             'username'      => 'test-username',    // valid username | ||||||
|  |             'password'      => 'testpass',         // valid password | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         // make the call to grant a crypto token | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); | ||||||
|  |         $this->assertNotNull($refreshToken = $response->getParameter('refresh_token')); | ||||||
|  |  | ||||||
|  |         // decode token and make sure refresh_token isn't set | ||||||
|  |         list($header, $payload, $signature) = explode('.', $JwtAccessToken); | ||||||
|  |         $decodedToken = json_decode(base64_decode($payload), true); | ||||||
|  |         $this->assertFalse(array_key_exists('refresh_token', $decodedToken)); | ||||||
|  |  | ||||||
|  |         // use the refresh token to get another access token | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type'    => 'refresh_token', | ||||||
|  |             'client_id'     => 'Test Client ID',   // valid client id | ||||||
|  |             'client_secret' => 'TestSecret',       // valid client secret | ||||||
|  |             'refresh_token' => $refreshToken, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |         $this->assertNotNull($response->getParameter('access_token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getTestServer() | ||||||
|  |     { | ||||||
|  |         $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |  | ||||||
|  |         $storage = array( | ||||||
|  |             'access_token' => new JwtAccessTokenStorage($memoryStorage), | ||||||
|  |             'client' => $memoryStorage, | ||||||
|  |             'client_credentials' => $memoryStorage, | ||||||
|  |         ); | ||||||
|  |         $server = new Server($storage); | ||||||
|  |         $server->addGrantType(new ClientCredentials($memoryStorage)); | ||||||
|  |  | ||||||
|  |         // make the "token" response type a JwtAccessToken | ||||||
|  |         $config = array('issuer' => 'https://api.example.com'); | ||||||
|  |         $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, null, $config)); | ||||||
|  |  | ||||||
|  |         return $server; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								library/oauth2/test/OAuth2/ScopeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								library/oauth2/test/OAuth2/ScopeTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Storage\Memory; | ||||||
|  |  | ||||||
|  | class ScopeTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     public function testCheckScope() | ||||||
|  |     { | ||||||
|  |         $scopeUtil = new Scope(); | ||||||
|  |  | ||||||
|  |         $this->assertFalse($scopeUtil->checkScope('invalid', 'list of scopes')); | ||||||
|  |         $this->assertTrue($scopeUtil->checkScope('valid', 'valid and-some other-scopes')); | ||||||
|  |         $this->assertTrue($scopeUtil->checkScope('valid another-valid', 'valid another-valid and-some other-scopes')); | ||||||
|  |         // all scopes must match | ||||||
|  |         $this->assertFalse($scopeUtil->checkScope('valid invalid', 'valid and-some other-scopes')); | ||||||
|  |         $this->assertFalse($scopeUtil->checkScope('valid valid2 invalid', 'valid valid2 and-some other-scopes')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testScopeStorage() | ||||||
|  |     { | ||||||
|  |         $scopeUtil = new Scope(); | ||||||
|  |         $this->assertEquals($scopeUtil->getDefaultScope(), null); | ||||||
|  |  | ||||||
|  |         $scopeUtil = new Scope(array( | ||||||
|  |             'default_scope' => 'default', | ||||||
|  |             'supported_scopes' => array('this', 'that', 'another'), | ||||||
|  |         )); | ||||||
|  |         $this->assertEquals($scopeUtil->getDefaultScope(), 'default'); | ||||||
|  |         $this->assertTrue($scopeUtil->scopeExists('this that another', 'client_id')); | ||||||
|  |  | ||||||
|  |         $memoryStorage = new Memory(array( | ||||||
|  |             'default_scope' => 'base', | ||||||
|  |             'supported_scopes' => array('only-this-one'), | ||||||
|  |         )); | ||||||
|  |         $scopeUtil = new Scope($memoryStorage); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($scopeUtil->getDefaultScope(), 'base'); | ||||||
|  |         $this->assertTrue($scopeUtil->scopeExists('only-this-one', 'client_id')); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										684
									
								
								library/oauth2/test/OAuth2/ServerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										684
									
								
								library/oauth2/test/OAuth2/ServerTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,684 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2; | ||||||
|  |  | ||||||
|  | use OAuth2\Request\TestRequest; | ||||||
|  | use OAuth2\ResponseType\AuthorizationCode; | ||||||
|  | use OAuth2\Storage\Bootstrap; | ||||||
|  |  | ||||||
|  | class ServerTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\ClientInterface | ||||||
|  |      **/ | ||||||
|  |     public function testGetAuthorizeControllerWithNoClientStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         // must set Client Storage | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\AccessTokenInterface | ||||||
|  |      **/ | ||||||
|  |     public function testGetAuthorizeControllerWithNoAccessTokenStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         // must set AccessToken or AuthorizationCode | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetAuthorizeControllerWithClientStorageAndAccessTokenResponseType() | ||||||
|  |     { | ||||||
|  |         // must set AccessToken or AuthorizationCode | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->addResponseType($this->getMock('OAuth2\ResponseType\AccessTokenInterface')); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeResponseType() | ||||||
|  |     { | ||||||
|  |         // must set AccessToken or AuthorizationCode | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->addResponseType($this->getMock('OAuth2\ResponseType\AuthorizationCodeInterface')); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException allow_implicit | ||||||
|  |      **/ | ||||||
|  |     public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         // must set AuthorizationCode or AccessToken / implicit | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorage() | ||||||
|  |     { | ||||||
|  |         // must set AuthorizationCode or AccessToken / implicit | ||||||
|  |         $server = new Server(array(), array('allow_implicit' => true)); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeStorage() | ||||||
|  |     { | ||||||
|  |         // must set AccessToken or AuthorizationCode | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException grant_types | ||||||
|  |      **/ | ||||||
|  |     public function testGetTokenControllerWithGrantTypeStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\ClientCredentialsInterface | ||||||
|  |      **/ | ||||||
|  |     public function testGetTokenControllerWithNoClientCredentialsStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\UserCredentialsInterface')); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\AccessTokenInterface | ||||||
|  |      **/ | ||||||
|  |     public function testGetTokenControllerWithNoAccessTokenStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetTokenControllerWithAccessTokenAndClientCredentialsStorage() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStorageAndGrantTypes() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); | ||||||
|  |         $server->addGrantType($this->getMockBuilder('OAuth2\GrantType\AuthorizationCode')->disableOriginalConstructor()->getMock()); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\AccessTokenInterface | ||||||
|  |      **/ | ||||||
|  |     public function testGetResourceControllerWithNoAccessTokenStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->getResourceController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetResourceControllerWithAccessTokenStorage() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); | ||||||
|  |         $server->getResourceController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException InvalidArgumentException OAuth2\Storage\AccessTokenInterface | ||||||
|  |      **/ | ||||||
|  |     public function testAddingStorageWithInvalidClass() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage(new \StdClass()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException InvalidArgumentException access_token | ||||||
|  |      **/ | ||||||
|  |     public function testAddingStorageWithInvalidKey() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'nonexistant_storage'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException InvalidArgumentException OAuth2\Storage\AuthorizationCodeInterface | ||||||
|  |      **/ | ||||||
|  |     public function testAddingStorageWithInvalidKeyStorageCombination() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'authorization_code'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddingStorageWithValidKeyOnlySetsThatKey() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\Memory'), 'access_token'); | ||||||
|  |  | ||||||
|  |         $reflection = new \ReflectionClass($server); | ||||||
|  |         $prop = $reflection->getProperty('storages'); | ||||||
|  |         $prop->setAccessible(true); | ||||||
|  |  | ||||||
|  |         $storages = $prop->getValue($server); // get the private "storages" property | ||||||
|  |  | ||||||
|  |         $this->assertEquals(1, count($storages)); | ||||||
|  |         $this->assertTrue(isset($storages['access_token'])); | ||||||
|  |         $this->assertFalse(isset($storages['authorization_code'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddingClientStorageSetsClientCredentialsStorageByDefault() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $memory = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |         $server->addStorage($memory, 'client'); | ||||||
|  |  | ||||||
|  |         $client_credentials = $server->getStorage('client_credentials'); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($client_credentials); | ||||||
|  |         $this->assertEquals($client_credentials, $memory); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddStorageWithNullValue() | ||||||
|  |     { | ||||||
|  |         $memory = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |         $server = new Server($memory); | ||||||
|  |         $server->addStorage(null, 'refresh_token'); | ||||||
|  |  | ||||||
|  |         $client_credentials = $server->getStorage('client_credentials'); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($client_credentials); | ||||||
|  |         $this->assertEquals($client_credentials, $memory); | ||||||
|  |  | ||||||
|  |         $refresh_token = $server->getStorage('refresh_token'); | ||||||
|  |  | ||||||
|  |         $this->assertNull($refresh_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testNewServerWithNullStorageValue() | ||||||
|  |     { | ||||||
|  |         $memory = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |         $server = new Server(array( | ||||||
|  |             'client_credentials' => $memory, | ||||||
|  |             'refresh_token'      => null, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $client_credentials = $server->getStorage('client_credentials'); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($client_credentials); | ||||||
|  |         $this->assertEquals($client_credentials, $memory); | ||||||
|  |  | ||||||
|  |         $refresh_token = $server->getStorage('refresh_token'); | ||||||
|  |  | ||||||
|  |         $this->assertNull($refresh_token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddingClientCredentialsStorageSetsClientStorageByDefault() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $memory = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |         $server->addStorage($memory, 'client_credentials'); | ||||||
|  |  | ||||||
|  |         $client = $server->getStorage('client'); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($client); | ||||||
|  |         $this->assertEquals($client, $memory); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSettingClientStorageByDefaultDoesNotOverrideSetStorage() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $pdo = $this->getMockBuilder('OAuth2\Storage\Pdo') | ||||||
|  |             ->disableOriginalConstructor()->getMock(); | ||||||
|  |  | ||||||
|  |         $memory = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |  | ||||||
|  |         $server->addStorage($pdo, 'client'); | ||||||
|  |         $server->addStorage($memory, 'client_credentials'); | ||||||
|  |  | ||||||
|  |         $client = $server->getStorage('client'); | ||||||
|  |         $client_credentials = $server->getStorage('client_credentials'); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($client, $pdo); | ||||||
|  |         $this->assertEquals($client_credentials, $memory); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddingResponseType() | ||||||
|  |     { | ||||||
|  |         $storage = $this->getMock('OAuth2\Storage\Memory'); | ||||||
|  |         $storage | ||||||
|  |           ->expects($this->any()) | ||||||
|  |           ->method('getClientDetails') | ||||||
|  |           ->will($this->returnValue(array('client_id' => 'some_client'))); | ||||||
|  |         $storage | ||||||
|  |           ->expects($this->any()) | ||||||
|  |           ->method('checkRestrictedGrantType') | ||||||
|  |           ->will($this->returnValue(true)); | ||||||
|  |  | ||||||
|  |         // add with the "code" key explicitly set | ||||||
|  |         $codeType = new AuthorizationCode($storage); | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addStorage($storage); | ||||||
|  |         $server->addResponseType($codeType); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'client_id' => 'some_client', | ||||||
|  |             'redirect_uri' => 'http://example.com', | ||||||
|  |             'state' => 'xyx', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         // the response is successful | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |         $this->assertTrue(isset($query['code'])); | ||||||
|  |         $this->assertFalse(isset($query['error'])); | ||||||
|  |  | ||||||
|  |         // add with the "code" key not set | ||||||
|  |         $codeType = new AuthorizationCode($storage); | ||||||
|  |         $server = new Server(array($storage), array(), array(), array($codeType)); | ||||||
|  |         $request = new Request(array( | ||||||
|  |             'response_type' => 'code', | ||||||
|  |             'client_id' => 'some_client', | ||||||
|  |             'redirect_uri' => 'http://example.com', | ||||||
|  |             'state' => 'xyx', | ||||||
|  |         )); | ||||||
|  |         $server->handleAuthorizeRequest($request, $response = new Response(), true); | ||||||
|  |  | ||||||
|  |         // the response is successful | ||||||
|  |         $this->assertEquals($response->getStatusCode(), 302); | ||||||
|  |         $parts = parse_url($response->getHttpHeader('Location')); | ||||||
|  |         parse_str($parts['query'], $query); | ||||||
|  |         $this->assertTrue(isset($query['code'])); | ||||||
|  |         $this->assertFalse(isset($query['error'])); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testCustomClientAssertionType() | ||||||
|  |     { | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'authorization_code', | ||||||
|  |             'client_id' =>'Test Client ID', | ||||||
|  |             'code' => 'testcode', | ||||||
|  |         )); | ||||||
|  |         // verify the mock clientAssertionType was called as expected | ||||||
|  |         $clientAssertionType = $this->getMock('OAuth2\ClientAssertionType\ClientAssertionTypeInterface', array('validateRequest', 'getClientId')); | ||||||
|  |         $clientAssertionType | ||||||
|  |             ->expects($this->once()) | ||||||
|  |             ->method('validateRequest') | ||||||
|  |             ->will($this->returnValue(true)); | ||||||
|  |         $clientAssertionType | ||||||
|  |             ->expects($this->once()) | ||||||
|  |             ->method('getClientId') | ||||||
|  |             ->will($this->returnValue('Test Client ID')); | ||||||
|  |  | ||||||
|  |         // create mock storage | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server(array($storage), array(), array(), array(), null, null, $clientAssertionType); | ||||||
|  |         $server->handleTokenRequest($request, $response = new Response()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHttpBasicConfig() | ||||||
|  |     { | ||||||
|  |         // create mock storage | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server(array($storage), array( | ||||||
|  |             'allow_credentials_in_request_body' => false, | ||||||
|  |             'allow_public_clients' => false | ||||||
|  |         )); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |         $httpBasic = $server->getClientAssertionType(); | ||||||
|  |  | ||||||
|  |         $reflection = new \ReflectionClass($httpBasic); | ||||||
|  |         $prop = $reflection->getProperty('config'); | ||||||
|  |         $prop->setAccessible(true); | ||||||
|  |  | ||||||
|  |         $config = $prop->getValue($httpBasic); // get the private "config" property | ||||||
|  |  | ||||||
|  |         $this->assertEquals($config['allow_credentials_in_request_body'], false); | ||||||
|  |         $this->assertEquals($config['allow_public_clients'], false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRefreshTokenConfig() | ||||||
|  |     { | ||||||
|  |         // create mock storage | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server1 = new Server(array($storage)); | ||||||
|  |         $server2 = new Server(array($storage), array('always_issue_new_refresh_token' => true, 'unset_refresh_token_after_use' => false)); | ||||||
|  |  | ||||||
|  |         $server1->getTokenController(); | ||||||
|  |         $refreshToken1 = $server1->getGrantType('refresh_token'); | ||||||
|  |  | ||||||
|  |         $server2->getTokenController(); | ||||||
|  |         $refreshToken2 = $server2->getGrantType('refresh_token'); | ||||||
|  |  | ||||||
|  |         $reflection1 = new \ReflectionClass($refreshToken1); | ||||||
|  |         $prop1 = $reflection1->getProperty('config'); | ||||||
|  |         $prop1->setAccessible(true); | ||||||
|  |  | ||||||
|  |         $reflection2 = new \ReflectionClass($refreshToken2); | ||||||
|  |         $prop2 = $reflection2->getProperty('config'); | ||||||
|  |         $prop2->setAccessible(true); | ||||||
|  |  | ||||||
|  |         // get the private "config" property | ||||||
|  |         $config1 = $prop1->getValue($refreshToken1); | ||||||
|  |         $config2 = $prop2->getValue($refreshToken2); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($config1['always_issue_new_refresh_token'], false); | ||||||
|  |         $this->assertEquals($config2['always_issue_new_refresh_token'], true); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($config1['unset_refresh_token_after_use'], true); | ||||||
|  |         $this->assertEquals($config2['unset_refresh_token_after_use'], false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Test setting "always_issue_new_refresh_token" on a server level | ||||||
|  |      * | ||||||
|  |      * @see test/OAuth2/GrantType/RefreshTokenTest::testValidRefreshTokenWithNewRefreshTokenInResponse | ||||||
|  |      **/ | ||||||
|  |     public function testValidRefreshTokenWithNewRefreshTokenInResponse() | ||||||
|  |     { | ||||||
|  |         $storage = Bootstrap::getInstance()->getMemoryStorage(); | ||||||
|  |         $server = new Server($storage, array('always_issue_new_refresh_token' => true)); | ||||||
|  |  | ||||||
|  |         $request = TestRequest::createPost(array( | ||||||
|  |             'grant_type' => 'refresh_token', // valid grant type | ||||||
|  |             'client_id' => 'Test Client ID', // valid client id | ||||||
|  |             'client_secret' => 'TestSecret', // valid client secret | ||||||
|  |             'refresh_token' => 'test-refreshtoken', // valid refresh token | ||||||
|  |         )); | ||||||
|  |         $token = $server->grantAccessToken($request, new Response()); | ||||||
|  |         $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); | ||||||
|  |  | ||||||
|  |         $refresh_token = $storage->getRefreshToken($token['refresh_token']); | ||||||
|  |         $this->assertNotNull($refresh_token); | ||||||
|  |         $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']); | ||||||
|  |         $this->assertEquals($refresh_token['client_id'], $request->request('client_id')); | ||||||
|  |         $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used'); | ||||||
|  |         $used_token = $storage->getRefreshToken('test-refreshtoken'); | ||||||
|  |         $this->assertFalse($used_token, 'the refresh token used is no longer valid'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException InvalidArgumentException OAuth2\ResponseType\AuthorizationCodeInterface | ||||||
|  |      **/ | ||||||
|  |     public function testAddingUnknownResponseTypeThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addResponseType($this->getMock('OAuth2\ResponseType\ResponseTypeInterface')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\PublicKeyInterface | ||||||
|  |      **/ | ||||||
|  |     public function testUsingJwtAccessTokensWithoutPublicKeyStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $server = new Server(array(), array('use_jwt_access_tokens' => true)); | ||||||
|  |         $server->addGrantType($this->getMock('OAuth2\GrantType\GrantTypeInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); | ||||||
|  |         $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); | ||||||
|  |  | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingJustJwtAccessTokenStorageWithResourceControllerIsOkay() | ||||||
|  |     { | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); | ||||||
|  |  | ||||||
|  |         $this->assertNotNull($server->getResourceController()); | ||||||
|  |         $this->assertInstanceOf('OAuth2\Storage\PublicKeyInterface', $server->getStorage('public_key')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\Storage\ClientInterface | ||||||
|  |      **/ | ||||||
|  |     public function testUsingJustJwtAccessTokenStorageWithAuthorizeControllerThrowsException() | ||||||
|  |     { | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException grant_types | ||||||
|  |      **/ | ||||||
|  |     public function testUsingJustJwtAccessTokenStorageWithTokenControllerThrowsException() | ||||||
|  |     { | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); | ||||||
|  |         $server->getTokenController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingJwtAccessTokenAndClientStorageWithAuthorizeControllerIsOkay() | ||||||
|  |     { | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $server = new Server(array($pubkey, $client), array('use_jwt_access_tokens' => true, 'allow_implicit' => true)); | ||||||
|  |         $this->assertNotNull($server->getAuthorizeController()); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\ResponseType\JwtAccessToken', $server->getResponseType('token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException UserClaims | ||||||
|  |      **/ | ||||||
|  |     public function testUsingOpenIDConnectWithoutUserClaimsThrowsException() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $server = new Server($client, array('use_openid_connect' => true)); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException PublicKeyInterface | ||||||
|  |      **/ | ||||||
|  |     public function testUsingOpenIDConnectWithoutPublicKeyThrowsException() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OPenID\Storage\UserClaimsInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims), array('use_openid_connect' => true)); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException issuer | ||||||
|  |      **/ | ||||||
|  |     public function testUsingOpenIDConnectWithoutIssuerThrowsException() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey), array('use_openid_connect' => true)); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingOpenIDConnectWithIssuerPublicKeyAndUserClaimsIsOkay() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy', | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); | ||||||
|  |         $this->assertNull($server->getResponseType('id_token token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\ResponseType\AccessTokenInterface | ||||||
|  |      **/ | ||||||
|  |     public function testUsingOpenIDConnectWithAllowImplicitWithoutTokenStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy', | ||||||
|  |             'allow_implicit' => true, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingOpenIDConnectWithAllowImplicitAndUseJwtAccessTokensIsOkay() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy', | ||||||
|  |             'allow_implicit' => true, | ||||||
|  |             'use_jwt_access_tokens' => true, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenStorageIsOkay() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey, $token), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy', | ||||||
|  |             'allow_implicit' => true, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenResponseTypeIsOkay() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         // $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy', | ||||||
|  |             'allow_implicit' => true, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $token = $this->getMock('OAuth2\ResponseType\AccessTokenInterface'); | ||||||
|  |         $server->addResponseType($token, 'token'); | ||||||
|  |  | ||||||
|  |         $server->getAuthorizeController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @expectedException LogicException OAuth2\OpenID\Storage\AuthorizationCodeInterface | ||||||
|  |      **/ | ||||||
|  |     public function testUsingOpenIDConnectWithAuthorizationCodeStorageThrowsException() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); | ||||||
|  |         $authcode = $this->getMock('OAuth2\Storage\AuthorizationCodeInterface'); | ||||||
|  |  | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getTokenController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testUsingOpenIDConnectWithOpenIDAuthorizationCodeStorageCreatesOpenIDAuthorizationCodeGrantType() | ||||||
|  |     { | ||||||
|  |         $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface'); | ||||||
|  |         $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); | ||||||
|  |         $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); | ||||||
|  |         $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); | ||||||
|  |         $authcode = $this->getMock('OAuth2\OpenID\Storage\AuthorizationCodeInterface'); | ||||||
|  |  | ||||||
|  |         $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array( | ||||||
|  |             'use_openid_connect' => true, | ||||||
|  |             'issuer' => 'someguy' | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $server->getTokenController(); | ||||||
|  |  | ||||||
|  |         $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testMultipleValuedResponseTypeOrderDoesntMatter() | ||||||
|  |     { | ||||||
|  |         $responseType = $this->getMock('OAuth2\OpenID\ResponseType\IdTokenTokenInterface'); | ||||||
|  |         $server = new Server(array(), array(), array(), array( | ||||||
|  |             'token id_token' => $responseType, | ||||||
|  |         )); | ||||||
|  |  | ||||||
|  |         $this->assertEquals($responseType, $server->getResponseType('id_token token')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddGrantTypeWithoutKey() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface'))); | ||||||
|  |  | ||||||
|  |         $grantTypes = $server->getGrantTypes(); | ||||||
|  |         $this->assertEquals('authorization_code', key($grantTypes)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddGrantTypeWithKey() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 'ac'); | ||||||
|  |  | ||||||
|  |         $grantTypes = $server->getGrantTypes(); | ||||||
|  |         $this->assertEquals('ac', key($grantTypes)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddGrantTypeWithKeyNotString() | ||||||
|  |     { | ||||||
|  |         $server = new Server(); | ||||||
|  |         $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 42); | ||||||
|  |  | ||||||
|  |         $grantTypes = $server->getGrantTypes(); | ||||||
|  |         $this->assertEquals('authorization_code', key($grantTypes)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								library/oauth2/test/OAuth2/Storage/AccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								library/oauth2/test/OAuth2/Storage/AccessTokenTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace OAuth2\Storage; | ||||||
|  |  | ||||||
|  | class AccessTokenTest extends BaseTest | ||||||
|  | { | ||||||
|  |     /** @dataProvider provideStorage */ | ||||||
|  |     public function testSetAccessToken(AccessTokenInterface $storage) | ||||||
|  |     { | ||||||
|  |         if ($storage instanceof NullStorage) { | ||||||
|  |             $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // assert token we are about to add does not exist | ||||||
|  |         $token = $storage->getAccessToken('newtoken'); | ||||||
|  |         $this->assertFalse($token); | ||||||
|  |  | ||||||
|  |         // add new token | ||||||
|  |         $expires = time() + 20; | ||||||
|  |         $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEUSERID', $expires); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         $token = $storage->getAccessToken('newtoken'); | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('client_id', $token); | ||||||
|  |         $this->assertArrayHasKey('user_id', $token); | ||||||
|  |         $this->assertArrayHasKey('expires', $token); | ||||||
|  |         $this->assertEquals($token['access_token'], 'newtoken'); | ||||||
|  |         $this->assertEquals($token['client_id'], 'client ID'); | ||||||
|  |         $this->assertEquals($token['user_id'], 'SOMEUSERID'); | ||||||
|  |         $this->assertEquals($token['expires'], $expires); | ||||||
|  |  | ||||||
|  |         // change existing token | ||||||
|  |         $expires = time() + 42; | ||||||
|  |         $success = $storage->setAccessToken('newtoken', 'client ID2', 'SOMEOTHERID', $expires); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         $token = $storage->getAccessToken('newtoken'); | ||||||
|  |         $this->assertNotNull($token); | ||||||
|  |         $this->assertArrayHasKey('access_token', $token); | ||||||
|  |         $this->assertArrayHasKey('client_id', $token); | ||||||
|  |         $this->assertArrayHasKey('user_id', $token); | ||||||
|  |         $this->assertArrayHasKey('expires', $token); | ||||||
|  |         $this->assertEquals($token['access_token'], 'newtoken'); | ||||||
|  |         $this->assertEquals($token['client_id'], 'client ID2'); | ||||||
|  |         $this->assertEquals($token['user_id'], 'SOMEOTHERID'); | ||||||
|  |         $this->assertEquals($token['expires'], $expires); | ||||||
|  |  | ||||||
|  |         // add token with scope having an empty string value | ||||||
|  |         $expires = time() + 42; | ||||||
|  |         $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEOTHERID', $expires, ''); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideStorage */ | ||||||
|  |     public function testUnsetAccessToken(AccessTokenInterface $storage) | ||||||
|  |     { | ||||||
|  |         if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) { | ||||||
|  |             $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // assert token we are about to unset does not exist | ||||||
|  |         $token = $storage->getAccessToken('revokabletoken'); | ||||||
|  |         $this->assertFalse($token); | ||||||
|  |  | ||||||
|  |         // add new token | ||||||
|  |         $expires = time() + 20; | ||||||
|  |         $success = $storage->setAccessToken('revokabletoken', 'client ID', 'SOMEUSERID', $expires); | ||||||
|  |         $this->assertTrue($success); | ||||||
|  |  | ||||||
|  |         // assert unsetAccessToken returns true | ||||||
|  |         $result = $storage->unsetAccessToken('revokabletoken'); | ||||||
|  |         $this->assertTrue($result); | ||||||
|  |  | ||||||
|  |         // assert token we unset does not exist | ||||||
|  |         $token = $storage->getAccessToken('revokabletoken'); | ||||||
|  |         $this->assertFalse($token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @dataProvider provideStorage */ | ||||||
|  |     public function testUnsetAccessTokenReturnsFalse(AccessTokenInterface $storage) | ||||||
|  |     { | ||||||
|  |         if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) { | ||||||
|  |             $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // assert token we are about to unset does not exist | ||||||
|  |         $token = $storage->getAccessToken('nonexistanttoken'); | ||||||
|  |         $this->assertFalse($token); | ||||||
|  |  | ||||||
|  |         // assert unsetAccessToken returns false | ||||||
|  |         $result = $storage->unsetAccessToken('nonexistanttoken'); | ||||||
|  |         $this->assertFalse($result); | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user