diff options
Diffstat (limited to 'vendor')
349 files changed, 17673 insertions, 1767 deletions
diff --git a/vendor/autoload.php b/vendor/autoload.php index 8b4926c3d..063a1b7e1 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -2,6 +2,6 @@ // autoload.php @generated by Composer -require_once __DIR__ . '/composer/autoload_real.php'; +require_once __DIR__ . '/composer' . '/autoload_real.php'; return ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d::getLoader(); diff --git a/vendor/bshaffer/oauth2-server-php/CHANGELOG.md b/vendor/bshaffer/oauth2-server-php/CHANGELOG.md new file mode 100644 index 000000000..4fddd72c9 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/CHANGELOG.md @@ -0,0 +1,182 @@ +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.9.0 (2016-01-06) + + PR: https://github.com/bshaffer/oauth2-server-php/pull/788 + + * bug #645 - Allow null for client_secret + * bug #651 - Fix bug in isPublicClient of Cassandra Storage + * bug #670 - Bug in client's scope restriction + * bug #672 - Implemented method to override the password hashing algorithm + * bug #698 - Fix Token Response's Content-Type to application/json + * bug #729 - Ensures unsetAccessToken and unsetRefreshToken return a bool + * bug #749 - Fix UserClaims for CodeIdToken + * bug #784 - RFC6750 compatibility + * bug #776 - Fix "redirect_uri_mismatch" for URIs with encoded characters + * bug #759 - no access token supplied to resource controller results in empty request body + * bug #773 - Use OpenSSL random method before attempting Mcrypt's. + * bug #790 - Add mongo db + +* 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.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 + * 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 diff --git a/vendor/bshaffer/oauth2-server-php/LICENSE b/vendor/bshaffer/oauth2-server-php/LICENSE new file mode 100644 index 000000000..d7ece8467 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/LICENSE @@ -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. diff --git a/vendor/bshaffer/oauth2-server-php/README.md b/vendor/bshaffer/oauth2-server-php/README.md new file mode 100644 index 000000000..4ceda6cf9 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/README.md @@ -0,0 +1,8 @@ +oauth2-server-php +================= + +[![Build Status](https://travis-ci.org/bshaffer/oauth2-server-php.svg?branch=develop)](https://travis-ci.org/bshaffer/oauth2-server-php) + +[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php) + +View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/)
\ No newline at end of file diff --git a/vendor/bshaffer/oauth2-server-php/composer.json b/vendor/bshaffer/oauth2-server-php/composer.json new file mode 100644 index 000000000..561699f5e --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/composer.json @@ -0,0 +1,34 @@ +{ + "name": "bshaffer/oauth2-server-php", + "description":"OAuth2 Server for PHP", + "keywords":["oauth","oauth2","auth"], + "type":"library", + "license":"MIT", + "authors":[ + { + "name":"Brent Shaffer", + "email": "bshafs@gmail.com", + "homepage":"http://brentertainment.com" + } + ], + "homepage": "http://github.com/bshaffer/oauth2-server-php", + "autoload": { + "psr-0": { "OAuth2": "src/" } + }, + "require":{ + "php":">=5.3.9" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.8", + "firebase/php-jwt": "~2.2", + "predis/predis": "dev-master", + "thobbs/phpcassa": "dev-master", + "mongodb/mongodb": "^1.1" + }, + "suggest": { + "predis/predis": "Required to use Redis storage", + "thobbs/phpcassa": "Required to use Cassandra storage", + "aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage", + "firebase/php-jwt": "~1.1 is required to use MondoDB storage" + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php new file mode 100644 index 000000000..ecfb6ba75 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php @@ -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; + } + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php new file mode 100644 index 000000000..29c7171b5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php @@ -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(); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php new file mode 100644 index 000000000..0ecb7e18d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php new file mode 100644 index 000000000..ea7f54a87 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php @@ -0,0 +1,393 @@ +<?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; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * @return bool + */ + 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 = preg_split('/\s+/', $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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php new file mode 100644 index 000000000..fa07ae8d2 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php new file mode 100644 index 000000000..3cfaaaf12 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php @@ -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, 'invalid_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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php new file mode 100644 index 000000000..611421935 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php new file mode 100644 index 000000000..5d2d731fe --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php @@ -0,0 +1,295 @@ +<?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 +{ + /** + * @var AccessTokenInterface + */ + protected $accessToken; + + /** + * @var array + */ + protected $grantTypes; + + /** + * @var ClientAssertionTypeInterface + */ + protected $clientAssertionType; + + /** + * @var Scope|ScopeInterface + */ + protected $scopeUtil; + + /** + * @var ClientInterface + */ + 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 RequestInterface $request Request object to grant access token + * @param ResponseInterface $response + * + * @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 GrantTypeInterface $grantType the grant type to add for the specified identifier + * @param string $identifier 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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php new file mode 100644 index 000000000..72d72570f --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php new file mode 100644 index 000000000..2d336c664 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php new file mode 100644 index 000000000..1b527e0a0 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php new file mode 100644 index 000000000..ee576e643 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php new file mode 100644 index 000000000..cae9f787d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php @@ -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')) != urldecode($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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php new file mode 100644 index 000000000..f953e4e8d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php @@ -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()); + } + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php new file mode 100644 index 000000000..98489e9c1 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php new file mode 100644 index 000000000..bb11a6954 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php new file mode 100644 index 000000000..e55385222 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php new file mode 100644 index 000000000..f165538ba --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php new file mode 100644 index 000000000..c9b5c6af7 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php new file mode 100644 index 000000000..1e231d844 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php @@ -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'; +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php new file mode 100644 index 000000000..30cb942d0 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php new file mode 100644 index 000000000..a89049d49 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php new file mode 100644 index 000000000..8ed1edc26 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php new file mode 100644 index 000000000..8971954c5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php new file mode 100644 index 000000000..ea4779255 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php new file mode 100644 index 000000000..ac7764d6c --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php new file mode 100644 index 000000000..629adcca8 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php @@ -0,0 +1,9 @@ +<?php + +namespace OAuth2\OpenID\ResponseType; + +use OAuth2\ResponseType\ResponseTypeInterface; + +interface CodeIdTokenInterface extends ResponseTypeInterface +{ +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php new file mode 100644 index 000000000..97777fbf2 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php new file mode 100644 index 000000000..0bd2f8391 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php new file mode 100644 index 000000000..f0c59799b --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php new file mode 100644 index 000000000..ac13e2032 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php @@ -0,0 +1,9 @@ +<?php + +namespace OAuth2\OpenID\ResponseType; + +use OAuth2\ResponseType\ResponseTypeInterface; + +interface IdTokenTokenInterface extends ResponseTypeInterface +{ +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php new file mode 100644 index 000000000..51dd867ec --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php new file mode 100644 index 000000000..f230bef9e --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php new file mode 100644 index 000000000..c92cee821 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php new file mode 100644 index 000000000..8a70d5fad --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php @@ -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(); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php new file mode 100644 index 000000000..fc1e62a98 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php @@ -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 $this->parameters ? 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]); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php new file mode 100644 index 000000000..c99b5f7d1 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php new file mode 100644 index 000000000..98f51218f --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php @@ -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('openssl_random_pseudo_bytes')) { + $randomData = openssl_random_pseudo_bytes(20); + if ($randomData !== false && strlen($randomData) === 20) { + return bin2hex($randomData); + } + } + if (function_exists('mcrypt_create_iv')) { + $randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM); + 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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php new file mode 100644 index 000000000..4bd3928d8 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php new file mode 100644 index 000000000..52aeb4be5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php @@ -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('openssl_random_pseudo_bytes')) { + $randomData = openssl_random_pseudo_bytes(100); + } elseif (function_exists('mcrypt_create_iv')) { + $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM); + } 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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php new file mode 100644 index 000000000..df777e221 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php new file mode 100644 index 000000000..3942fe41e --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php new file mode 100644 index 000000000..f8e26a5b0 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php @@ -0,0 +1,8 @@ +<?php + +namespace OAuth2\ResponseType; + +interface ResponseTypeInterface +{ + public function getAuthorizeResponse($params, $user_id = null); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php new file mode 100644 index 000000000..c44350bfd --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php @@ -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'); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php new file mode 100644 index 000000000..5b60f9aee --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php new file mode 100644 index 000000000..9cfcb83a5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php @@ -0,0 +1,879 @@ +<?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 + /** + * @var Response + */ + protected $response; + + /** + * @var array + */ + protected $config; + + /** + * @var array + */ + protected $storages; + + // servers + /** + * @var AuthorizeControllerInterface + */ + protected $authorizeController; + + /** + * @var TokenControllerInterface + */ + protected $tokenController; + + /** + * @var ResourceControllerInterface + */ + protected $resourceController; + + /** + * @var UserInfoControllerInterface + */ + protected $userInfoController; + + // config classes + protected $grantTypes; + protected $responseTypes; + protected $tokenType; + + /** + * @var ScopeInterface + */ + 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 + * + * @param AuthorizeControllerInterface $authorizeController + */ + public function setAuthorizeController(AuthorizeControllerInterface $authorizeController) + { + $this->authorizeController = $authorizeController; + } + + /** + * every getter deserves a setter + * + * @param TokenControllerInterface $tokenController + */ + public function setTokenController(TokenControllerInterface $tokenController) + { + $this->tokenController = $tokenController; + } + + /** + * every getter deserves a setter + * + * @param ResourceControllerInterface $resourceController + */ + public function setResourceController(ResourceControllerInterface $resourceController) + { + $this->resourceController = $resourceController; + } + + /** + * every getter deserves a setter + * + * @param UserInfoControllerInterface $userInfoController + */ + 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) + * + * @return ResponseInterface + * + * @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) + * + * @return ResponseInterface + * + * @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 ResponseInterface $response + * @param $is_authorized + * TRUE or FALSE depending on whether the user authorized the access. + * @param $user_id + * Identifier of user who authorized the client + * + * @return Response + * + * @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 + * + * @param ScopeInterface $scopeUtil + */ + 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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php new file mode 100644 index 000000000..1819158af --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php new file mode 100644 index 000000000..edc7c70e5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php @@ -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 expired + * + * @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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php new file mode 100644 index 000000000..c5048c08d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php @@ -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; + } + +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php new file mode 100644 index 000000000..3318c6966 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php new file mode 100644 index 000000000..09a5bffc1 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php new file mode 100755 index 000000000..1eb55f027 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php @@ -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.'); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php new file mode 100644 index 000000000..8347ab258 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php new file mode 100644 index 000000000..75b49d301 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php new file mode 100644 index 000000000..3abb2aa2d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php @@ -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 +{ + +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php new file mode 100644 index 000000000..c83aa72ea --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php new file mode 100644 index 000000000..42d833ccb --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php @@ -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'; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php new file mode 100644 index 000000000..eea06e315 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php @@ -0,0 +1,392 @@ +<?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, + PublicKeyInterface, + 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', + 'key_table' => 'oauth_keys', + '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.'); + } + + public function getPublicKey($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['public_key']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? false : $result['public_key']; + } + + public function getPrivateKey($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['private_key']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? false : $result['private_key']; + } + + public function getEncryptionAlgorithm($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['encryption_algorithm']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? 'RS256' : $result['encryption_algorithm']; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/MongoDB.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/MongoDB.php new file mode 100644 index 000000000..64f740fc1 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/MongoDB.php @@ -0,0 +1,380 @@ +<?php + +namespace OAuth2\Storage; + +use MongoDB\Client; +use MongoDB\Database; +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 MongoDB implements AuthorizationCodeInterface, + UserCredentialsInterface, + AccessTokenInterface, + ClientCredentialsInterface, + RefreshTokenInterface, + JwtBearerInterface, + PublicKeyInterface, + OpenIDAuthorizationCodeInterface +{ + protected $db; + protected $config; + + public function __construct($connection, $config = array()) + { + if ($connection instanceof Database) { + $this->db = $connection; + } else { + if (!is_array($connection)) { + throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB\Database or a configuration array'); + } + $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']); + $m = new Client($server); + $this->db = $m->selectDatabase($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', + 'jti_table' => 'oauth_jti', + 'scope_table' => 'oauth_scopes', + 'key_table' => 'oauth_keys', + ), $config); + } + + /* 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)) { + $result = $this->collection('client_table')->updateOne( + 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, + )) + ); + return $result->getMatchedCount() > 0; + } + $client = array( + 'client_id' => $client_id, + 'client_secret' => $client_secret, + 'redirect_uri' => $redirect_uri, + 'grant_types' => $grant_types, + 'scope' => $scope, + 'user_id' => $user_id, + ); + $result = $this->collection('client_table')->insertOne($client); + return $result->getInsertedCount() > 0; + } + + 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)) { + $result = $this->collection('access_token_table')->updateOne( + array('access_token' => $access_token), + array('$set' => array( + 'client_id' => $client_id, + 'expires' => $expires, + 'user_id' => $user_id, + 'scope' => $scope + )) + ); + return $result->getMatchedCount() > 0; + } + $token = array( + 'access_token' => $access_token, + 'client_id' => $client_id, + 'expires' => $expires, + 'user_id' => $user_id, + 'scope' => $scope + ); + $result = $this->collection('access_token_table')->insertOne($token); + return $result->getInsertedCount() > 0; + } + + public function unsetAccessToken($access_token) + { + $result = $this->collection('access_token_table')->deleteOne(array( + 'access_token' => $access_token + )); + return $result->getDeletedCount() > 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)) { + $result = $this->collection('code_table')->updateOne( + 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, + )) + ); + return $result->getMatchedCount() > 0; + } + $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, + ); + $result = $this->collection('code_table')->insertOne($token); + return $result->getInsertedCount() > 0; + } + + public function expireAuthorizationCode($code) + { + $result = $this->collection('code_table')->deleteOne(array( + 'authorization_code' => $code + )); + return $result->getDeletedCount() > 0; + } + + /* 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 + ); + $result = $this->collection('refresh_token_table')->insertOne($token); + return $result->getInsertedCount() > 0; + } + + public function unsetRefreshToken($refresh_token) + { + $result = $this->collection('refresh_token_table')->deleteOne(array( + 'refresh_token' => $refresh_token + )); + return $result->getDeletedCount() > 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)) { + $result = $this->collection('user_table')->updateOne( + array('username' => $username), + array('$set' => array( + 'password' => $password, + 'first_name' => $firstName, + 'last_name' => $lastName + )) + ); + + return $result->getMatchedCount() > 0; + } + + $user = array( + 'username' => $username, + 'password' => $password, + 'first_name' => $firstName, + 'last_name' => $lastName + ); + $result = $this->collection('user_table')->insertOne($user); + return $result->getInsertedCount() > 0; + } + + 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, $expires, $jti) + { + //TODO: Needs mongodb implementation. + throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.'); + } + + public function setJti($client_id, $subject, $audience, $expires, $jti) + { + //TODO: Needs mongodb implementation. + throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.'); + } + + public function getPublicKey($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['public_key']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? false : $result['public_key']; + } + + public function getPrivateKey($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['private_key']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? false : $result['private_key']; + } + + public function getEncryptionAlgorithm($client_id = null) + { + if ($client_id) { + $result = $this->collection('key_table')->findOne(array( + 'client_id' => $client_id + )); + if ($result) { + return $result['encryption_algorithm']; + } + } + + $result = $this->collection('key_table')->findOne(array( + 'client_id' => null + )); + return is_null($result) ? 'RS256' : $result['encryption_algorithm']; + } + + // Helper function to access a MongoDB collection by `type`: + protected function collection($name) + { + return $this->db->{$this->config[$name]}; + } +}
\ No newline at end of file diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php new file mode 100644 index 000000000..ae5107e29 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php new file mode 100644 index 000000000..108418d3a --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php new file mode 100644 index 000000000..e6294e22d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php @@ -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.'); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php new file mode 100644 index 000000000..e6407e440 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php @@ -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 expired. + * + * @ingroup oauth2_section_6 + */ + public function unsetRefreshToken($refresh_token); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php new file mode 100644 index 000000000..a8292269b --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php new file mode 100644 index 000000000..6e0fd7bad --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php new file mode 100644 index 000000000..8ac8596ac --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php @@ -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']); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php new file mode 100644 index 000000000..fe6a86aa6 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php @@ -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"); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php new file mode 100644 index 000000000..ad77d4a25 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php @@ -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); +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/AutoloadTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/AutoloadTest.php new file mode 100644 index 000000000..5901bdc42 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/AutoloadTest.php @@ -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')); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/AuthorizeControllerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/AuthorizeControllerTest.php new file mode 100644 index 000000000..3bfc760e4 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/AuthorizeControllerTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/ResourceControllerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/ResourceControllerTest.php new file mode 100644 index 000000000..b277514a5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/ResourceControllerTest.php @@ -0,0 +1,176 @@ +<?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')); + $this->assertEquals('', $response->getResponseBody()); + } + + 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'), 'invalid_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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/TokenControllerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/TokenControllerTest.php new file mode 100644 index 000000000..4a217bd55 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/TokenControllerTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/FirebaseJwtTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/FirebaseJwtTest.php new file mode 100644 index 000000000..d34136767 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/FirebaseJwtTest.php @@ -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), + ); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/JwtTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/JwtTest.php new file mode 100644 index 000000000..214eebac8 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/JwtTest.php @@ -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), + ); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/AuthorizationCodeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/AuthorizationCodeTest.php new file mode 100644 index 000000000..356b8e53c --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/AuthorizationCodeTest.php @@ -0,0 +1,223 @@ +<?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 testValidRedirectUri() + { + $server = $this->getTestServer(); + $request = TestRequest::createPost(array( + 'grant_type' => 'authorization_code', // valid grant type + 'client_id' => 'Test Client ID', // valid client id + 'redirect_uri' => 'http://brentertainment.com/voil%C3%A0', // valid client id + 'client_secret' => 'TestSecret', // valid client secret + 'code' => 'testcode-redirect-uri', // 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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ClientCredentialsTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ClientCredentialsTest.php new file mode 100644 index 000000000..f0d46ccb3 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ClientCredentialsTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ImplicitTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ImplicitTest.php new file mode 100644 index 000000000..a47aae3e8 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ImplicitTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/JwtBearerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/JwtBearerTest.php new file mode 100644 index 000000000..0a6c4b827 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/JwtBearerTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/RefreshTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/RefreshTokenTest.php new file mode 100644 index 000000000..a458aad8a --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/RefreshTokenTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/UserCredentialsTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/UserCredentialsTest.php new file mode 100644 index 000000000..18943d055 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/UserCredentialsTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php new file mode 100644 index 000000000..46de936d8 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php new file mode 100644 index 000000000..b1b687077 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php new file mode 100644 index 000000000..776002d1e --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php new file mode 100644 index 000000000..b0311434a --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTest.php new file mode 100644 index 000000000..e772f6be4 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php new file mode 100644 index 000000000..bc564d37b --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php new file mode 100644 index 000000000..bdfb085e3 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/UserClaimsTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/UserClaimsTest.php new file mode 100644 index 000000000..840f6c566 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/UserClaimsTest.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/RequestTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/RequestTest.php new file mode 100644 index 000000000..10db3215c --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/RequestTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseTest.php new file mode 100644 index 000000000..b8149005d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseTest.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/AccessTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/AccessTokenTest.php new file mode 100644 index 000000000..0ed1c82fc --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/AccessTokenTest.php @@ -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')); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/JwtAccessTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/JwtAccessTokenTest.php new file mode 100644 index 000000000..51b01a927 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/JwtAccessTokenTest.php @@ -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; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/ScopeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ScopeTest.php new file mode 100644 index 000000000..99f9cf6eb --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ScopeTest.php @@ -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')); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/ServerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ServerTest.php new file mode 100644 index 000000000..747e120f5 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/ServerTest.php @@ -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)); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AccessTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AccessTokenTest.php new file mode 100644 index 000000000..b34e0bfc0 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AccessTokenTest.php @@ -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); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AuthorizationCodeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AuthorizationCodeTest.php new file mode 100644 index 000000000..2d901b501 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AuthorizationCodeTest.php @@ -0,0 +1,106 @@ +<?php + +namespace OAuth2\Storage; + +class AuthorizationCodeTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testGetAuthorizationCode(AuthorizationCodeInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // nonexistant client_id + $details = $storage->getAuthorizationCode('faketoken'); + $this->assertFalse($details); + + // valid client_id + $details = $storage->getAuthorizationCode('testtoken'); + $this->assertNotNull($details); + } + + /** @dataProvider provideStorage */ + public function testSetAuthorizationCode(AuthorizationCodeInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // assert code we are about to add does not exist + $code = $storage->getAuthorizationCode('newcode'); + $this->assertFalse($code); + + // add new code + $expires = time() + 20; + $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires); + $this->assertTrue($success); + + $code = $storage->getAuthorizationCode('newcode'); + $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'], 'newcode'); + $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); + + // change existing code + $expires = time() + 42; + $success = $storage->setAuthorizationCode('newcode', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires); + $this->assertTrue($success); + + $code = $storage->getAuthorizationCode('newcode'); + $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'], 'newcode'); + $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); + + // add new code with scope having an empty string value + $expires = time() + 20; + $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, ''); + $this->assertTrue($success); + } + + /** @dataProvider provideStorage */ + public function testExpireAccessToken(AccessTokenInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // create a valid code + $expires = time() + 20; + $success = $storage->setAuthorizationCode('code-to-expire', 'client ID', 'SOMEUSERID', 'http://example.com', time() + 20); + $this->assertTrue($success); + + // verify the new code exists + $code = $storage->getAuthorizationCode('code-to-expire'); + $this->assertNotNull($code); + + $this->assertArrayHasKey('authorization_code', $code); + $this->assertEquals($code['authorization_code'], 'code-to-expire'); + + // now expire the code and ensure it's no longer available + $storage->expireAuthorizationCode('code-to-expire'); + $code = $storage->getAuthorizationCode('code-to-expire'); + $this->assertFalse($code); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientCredentialsTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientCredentialsTest.php new file mode 100644 index 000000000..15289af30 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientCredentialsTest.php @@ -0,0 +1,28 @@ +<?php + +namespace OAuth2\Storage; + +class ClientCredentialsTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testCheckClientCredentials(ClientCredentialsInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // nonexistant client_id + $pass = $storage->checkClientCredentials('fakeclient', 'testpass'); + $this->assertFalse($pass); + + // invalid password + $pass = $storage->checkClientCredentials('oauth_test_client', 'invalidcredentials'); + $this->assertFalse($pass); + + // valid credentials + $pass = $storage->checkClientCredentials('oauth_test_client', 'testpass'); + $this->assertTrue($pass); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientTest.php new file mode 100644 index 000000000..6a5cc0b49 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientTest.php @@ -0,0 +1,110 @@ +<?php + +namespace OAuth2\Storage; + +class ClientTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testGetClientDetails(ClientInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // nonexistant client_id + $details = $storage->getClientDetails('fakeclient'); + $this->assertFalse($details); + + // valid client_id + $details = $storage->getClientDetails('oauth_test_client'); + $this->assertNotNull($details); + $this->assertArrayHasKey('client_id', $details); + $this->assertArrayHasKey('client_secret', $details); + $this->assertArrayHasKey('redirect_uri', $details); + } + + /** @dataProvider provideStorage */ + public function testCheckRestrictedGrantType(ClientInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // Check invalid + $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'authorization_code'); + $this->assertFalse($pass); + + // Check valid + $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'implicit'); + $this->assertTrue($pass); + } + + /** @dataProvider provideStorage */ + public function testGetAccessToken(ClientInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // nonexistant client_id + $details = $storage->getAccessToken('faketoken'); + $this->assertFalse($details); + + // valid client_id + $details = $storage->getAccessToken('testtoken'); + $this->assertNotNull($details); + } + + /** @dataProvider provideStorage */ + public function testIsPublicClient(ClientInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + $publicClientId = 'public-client-'.rand(); + $confidentialClientId = 'confidential-client-'.rand(); + + // create a new client + $success1 = $storage->setClientDetails($publicClientId, ''); + $success2 = $storage->setClientDetails($confidentialClientId, 'some-secret'); + $this->assertTrue($success1); + $this->assertTrue($success2); + + // assert isPublicClient for both + $this->assertTrue($storage->isPublicClient($publicClientId)); + $this->assertFalse($storage->isPublicClient($confidentialClientId)); + } + + /** @dataProvider provideStorage */ + public function testSaveClient(ClientInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + $clientId = 'some-client-'.rand(); + + // create a new client + $success = $storage->setClientDetails($clientId, 'somesecret', 'http://test.com', 'client_credentials', 'clientscope1', 'brent@brentertainment.com'); + $this->assertTrue($success); + + // valid client_id + $details = $storage->getClientDetails($clientId); + $this->assertEquals($details['client_secret'], 'somesecret'); + $this->assertEquals($details['redirect_uri'], 'http://test.com'); + $this->assertEquals($details['grant_types'], 'client_credentials'); + $this->assertEquals($details['scope'], 'clientscope1'); + $this->assertEquals($details['user_id'], 'brent@brentertainment.com'); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/DynamoDBTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/DynamoDBTest.php new file mode 100644 index 000000000..2147f0914 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/DynamoDBTest.php @@ -0,0 +1,40 @@ +<?php + +namespace OAuth2\Storage; + +class DynamoDBTest extends BaseTest +{ + public function testGetDefaultScope() + { + $client = $this->getMockBuilder('\Aws\DynamoDb\DynamoDbClient') + ->disableOriginalConstructor() + ->setMethods(array('query')) + ->getMock(); + + $return = $this->getMockBuilder('\Guzzle\Service\Resource\Model') + ->setMethods(array('count', 'toArray')) + ->getMock(); + + $data = array( + 'Items' => array(), + 'Count' => 0, + 'ScannedCount'=> 0 + ); + + $return->expects($this->once()) + ->method('count') + ->will($this->returnValue(count($data))); + + $return->expects($this->once()) + ->method('toArray') + ->will($this->returnValue($data)); + + // should return null default scope if none is set in database + $client->expects($this->once()) + ->method('query') + ->will($this->returnValue($return)); + + $storage = new DynamoDB($client); + $this->assertNull($storage->getDefaultScope()); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtAccessTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtAccessTokenTest.php new file mode 100644 index 000000000..a6acbea1f --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtAccessTokenTest.php @@ -0,0 +1,41 @@ +<?php + +namespace OAuth2\Storage; + +use OAuth2\Encryption\Jwt; + +class JwtAccessTokenTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testSetAccessToken($storage) + { + if (!$storage instanceof PublicKey) { + // incompatible storage + return; + } + + $crypto = new jwtAccessToken($storage); + + $publicKeyStorage = Bootstrap::getInstance()->getMemoryStorage(); + $encryptionUtil = new Jwt(); + + $jwtAccessToken = array( + 'access_token' => rand(), + 'expires' => time() + 100, + 'scope' => 'foo', + ); + + $token = $encryptionUtil->encode($jwtAccessToken, $storage->getPrivateKey(), $storage->getEncryptionAlgorithm()); + + $this->assertNotNull($token); + + $tokenData = $crypto->getAccessToken($token); + + $this->assertTrue(is_array($tokenData)); + + /* assert the decoded token is the same */ + $this->assertEquals($tokenData['access_token'], $jwtAccessToken['access_token']); + $this->assertEquals($tokenData['expires'], $jwtAccessToken['expires']); + $this->assertEquals($tokenData['scope'], $jwtAccessToken['scope']); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtBearerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtBearerTest.php new file mode 100644 index 000000000..d0ab9b899 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtBearerTest.php @@ -0,0 +1,25 @@ +<?php + +namespace OAuth2\Storage; + +class JwtBearerTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testGetClientKey(JwtBearerInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // nonexistant client_id + $key = $storage->getClientKey('this-is-not-real', 'nor-is-this'); + $this->assertFalse($key); + + // valid client_id and subject + $key = $storage->getClientKey('oauth_test_client', 'test_subject'); + $this->assertNotNull($key); + $this->assertEquals($key, Bootstrap::getInstance()->getTestPublicKey()); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PdoTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PdoTest.php new file mode 100644 index 000000000..57eb39072 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PdoTest.php @@ -0,0 +1,39 @@ +<?php + +namespace OAuth2\Storage; + +class PdoTest extends BaseTest +{ + public function testCreatePdoStorageUsingPdoClass() + { + $pdo = new \PDO(sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir())); + $storage = new Pdo($pdo); + + $this->assertNotNull($storage->getClientDetails('oauth_test_client')); + } + + public function testCreatePdoStorageUsingDSN() + { + $dsn = sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir()); + $storage = new Pdo($dsn); + + $this->assertNotNull($storage->getClientDetails('oauth_test_client')); + } + + public function testCreatePdoStorageUsingConfig() + { + $config = array('dsn' => sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir())); + $storage = new Pdo($config); + + $this->assertNotNull($storage->getClientDetails('oauth_test_client')); + } + + /** + * @expectedException InvalidArgumentException dsn + */ + public function testCreatePdoStorageWithoutDSNThrowsException() + { + $config = array('username' => 'brent', 'password' => 'brentisaballer'); + $storage = new Pdo($config); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PublicKeyTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PublicKeyTest.php new file mode 100644 index 000000000..f85195870 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PublicKeyTest.php @@ -0,0 +1,29 @@ +<?php + +namespace OAuth2\Storage; + +class PublicKeyTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testSetAccessToken($storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + if (!$storage instanceof PublicKeyInterface) { + // incompatible storage + return; + } + + $configDir = Bootstrap::getInstance()->getConfigDir(); + $globalPublicKey = file_get_contents($configDir.'/keys/id_rsa.pub'); + $globalPrivateKey = file_get_contents($configDir.'/keys/id_rsa'); + + /* assert values from storage */ + $this->assertEquals($storage->getPublicKey(), $globalPublicKey); + $this->assertEquals($storage->getPrivateKey(), $globalPrivateKey); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/RefreshTokenTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/RefreshTokenTest.php new file mode 100644 index 000000000..314c93195 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/RefreshTokenTest.php @@ -0,0 +1,41 @@ +<?php + +namespace OAuth2\Storage; + +class RefreshTokenTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testSetRefreshToken(RefreshTokenInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // assert token we are about to add does not exist + $token = $storage->getRefreshToken('refreshtoken'); + $this->assertFalse($token); + + // add new token + $expires = time() + 20; + $success = $storage->setRefreshToken('refreshtoken', 'client ID', 'SOMEUSERID', $expires); + $this->assertTrue($success); + + $token = $storage->getRefreshToken('refreshtoken'); + $this->assertNotNull($token); + $this->assertArrayHasKey('refresh_token', $token); + $this->assertArrayHasKey('client_id', $token); + $this->assertArrayHasKey('user_id', $token); + $this->assertArrayHasKey('expires', $token); + $this->assertEquals($token['refresh_token'], 'refreshtoken'); + $this->assertEquals($token['client_id'], 'client ID'); + $this->assertEquals($token['user_id'], 'SOMEUSERID'); + $this->assertEquals($token['expires'], $expires); + + // add token with scope having an empty string value + $expires = time() + 20; + $success = $storage->setRefreshToken('refreshtoken2', 'client ID', 'SOMEUSERID', $expires, ''); + $this->assertTrue($success); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ScopeTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ScopeTest.php new file mode 100644 index 000000000..fd1edeb93 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ScopeTest.php @@ -0,0 +1,53 @@ +<?php + +namespace OAuth2\Storage; + +use OAuth2\Scope; + +class ScopeTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testScopeExists($storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + if (!$storage instanceof ScopeInterface) { + // incompatible storage + return; + } + + //Test getting scopes + $scopeUtil = new Scope($storage); + $this->assertTrue($scopeUtil->scopeExists('supportedscope1')); + $this->assertTrue($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3')); + $this->assertFalse($scopeUtil->scopeExists('fakescope')); + $this->assertFalse($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3 fakescope')); + } + + /** @dataProvider provideStorage */ + public function testGetDefaultScope($storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + if (!$storage instanceof ScopeInterface) { + // incompatible storage + return; + } + + // test getting default scope + $scopeUtil = new Scope($storage); + $expected = explode(' ', $scopeUtil->getDefaultScope()); + $actual = explode(' ', 'defaultscope1 defaultscope2'); + sort($expected); + sort($actual); + $this->assertEquals($expected, $actual); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/UserCredentialsTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/UserCredentialsTest.php new file mode 100644 index 000000000..65655a6b2 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/UserCredentialsTest.php @@ -0,0 +1,40 @@ +<?php + +namespace OAuth2\Storage; + +class UserCredentialsTest extends BaseTest +{ + /** @dataProvider provideStorage */ + public function testCheckUserCredentials(UserCredentialsInterface $storage) + { + if ($storage instanceof NullStorage) { + $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); + + return; + } + + // create a new user for testing + $success = $storage->setUser('testusername', 'testpass', 'Test', 'User'); + $this->assertTrue($success); + + // correct credentials + $this->assertTrue($storage->checkUserCredentials('testusername', 'testpass')); + // invalid password + $this->assertFalse($storage->checkUserCredentials('testusername', 'fakepass')); + // invalid username + $this->assertFalse($storage->checkUserCredentials('fakeusername', 'testpass')); + + // invalid username + $this->assertFalse($storage->getUserDetails('fakeusername')); + + // ensure all properties are set + $user = $storage->getUserDetails('testusername'); + $this->assertTrue($user !== false); + $this->assertArrayHasKey('user_id', $user); + $this->assertArrayHasKey('first_name', $user); + $this->assertArrayHasKey('last_name', $user); + $this->assertEquals($user['user_id'], 'testusername'); + $this->assertEquals($user['first_name'], 'Test'); + $this->assertEquals($user['last_name'], 'User'); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/OAuth2/TokenType/BearerTest.php b/vendor/bshaffer/oauth2-server-php/test/OAuth2/TokenType/BearerTest.php new file mode 100644 index 000000000..a2e000e22 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/OAuth2/TokenType/BearerTest.php @@ -0,0 +1,58 @@ +<?php + +namespace OAuth2\TokenType; + +use OAuth2\Request\TestRequest; +use OAuth2\Response; + +class BearerTest extends \PHPUnit_Framework_TestCase +{ + public function testValidContentTypeWithCharset() + { + $bearer = new Bearer(); + $request = TestRequest::createPost(array( + 'access_token' => 'ThisIsMyAccessToken' + )); + $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + + $param = $bearer->getAccessTokenParameter($request, $response = new Response()); + $this->assertEquals($param, 'ThisIsMyAccessToken'); + } + + public function testInvalidContentType() + { + $bearer = new Bearer(); + $request = TestRequest::createPost(array( + 'access_token' => 'ThisIsMyAccessToken' + )); + $request->server['CONTENT_TYPE'] = 'application/json; charset=UTF-8'; + + $param = $bearer->getAccessTokenParameter($request, $response = new Response()); + $this->assertNull($param); + $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 testValidRequestUsingAuthorizationHeader() + { + $bearer = new Bearer(); + $request = new TestRequest(); + $request->headers['AUTHORIZATION'] = 'Bearer MyToken'; + $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + + $param = $bearer->getAccessTokenParameter($request, $response = new Response()); + $this->assertEquals('MyToken', $param); + } + + public function testValidRequestUsingAuthorizationHeaderCaseInsensitive() + { + $bearer = new Bearer(); + $request = new TestRequest(); + $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + $request->headers['Authorization'] = 'Bearer MyToken'; + + $param = $bearer->getAccessTokenParameter($request, $response = new Response()); + $this->assertEquals('MyToken', $param); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/bootstrap.php b/vendor/bshaffer/oauth2-server-php/test/bootstrap.php new file mode 100644 index 000000000..0a4af0716 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/bootstrap.php @@ -0,0 +1,12 @@ +<?php + +require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); +OAuth2\Autoloader::register(); + +// register test classes +OAuth2\Autoloader::register(dirname(__FILE__).'/lib'); + +// register vendors if possible +if (file_exists(__DIR__.'/../vendor/autoload.php')) { + require_once(__DIR__.'/../vendor/autoload.php'); +} diff --git a/vendor/bshaffer/oauth2-server-php/test/cleanup.php b/vendor/bshaffer/oauth2-server-php/test/cleanup.php new file mode 100644 index 000000000..8663a901b --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/cleanup.php @@ -0,0 +1,15 @@ +<?php + +require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); +OAuth2\Autoloader::register(); + +// register test classes +OAuth2\Autoloader::register(dirname(__FILE__).'/lib'); + +// register vendors if possible +if (file_exists(__DIR__.'/../vendor/autoload.php')) { + require_once(__DIR__.'/../vendor/autoload.php'); +} + +// remove the dynamoDB database that was created for this build +OAuth2\Storage\Bootstrap::getInstance()->cleanupTravisDynamoDb(); diff --git a/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa b/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa new file mode 100644 index 000000000..e8b9eff2d --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV +8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN +QDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB +AoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA ++WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w +C6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb +oaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56 +1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0 +CPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg +VHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr +uxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo +cj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA +HoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R +-----END RSA PRIVATE KEY-----
\ No newline at end of file diff --git a/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa.pub b/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa.pub new file mode 100644 index 000000000..1ac15f5eb --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa.pub @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe +Fw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw +CQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs +NjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw +izIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu +Be+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K +vCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh +dGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD +lM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl +aViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL +FRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg== +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/vendor/bshaffer/oauth2-server-php/test/config/storage.json b/vendor/bshaffer/oauth2-server-php/test/config/storage.json new file mode 100644 index 000000000..52d3f2399 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/config/storage.json @@ -0,0 +1,188 @@ +{ + "authorization_codes": { + "testcode": { + "client_id": "Test Client ID", + "user_id": "", + "redirect_uri": "", + "expires": "9999999999", + "id_token": "IDTOKEN" + }, + "testcode-with-scope": { + "client_id": "Test Client ID", + "user_id": "", + "redirect_uri": "", + "expires": "9999999999", + "scope": "scope1 scope2" + }, + "testcode-expired": { + "client_id": "Test Client ID", + "user_id": "", + "redirect_uri": "", + "expires": "1356998400" + }, + "testcode-empty-secret": { + "client_id": "Test Client ID Empty Secret", + "user_id": "", + "redirect_uri": "", + "expires": "9999999999" + }, + "testcode-openid": { + "client_id": "Test Client ID", + "user_id": "", + "redirect_uri": "", + "expires": "9999999999", + "id_token": "test_id_token" + }, + "testcode-redirect-uri": { + "client_id": "Test Client ID", + "user_id": "", + "redirect_uri": "http://brentertainment.com/voil%C3%A0", + "expires": "9999999999", + "id_token": "IDTOKEN" + } + }, + "client_credentials" : { + "Test Client ID": { + "client_secret": "TestSecret" + }, + "Test Client ID with Redirect Uri": { + "client_secret": "TestSecret2", + "redirect_uri": "http://brentertainment.com" + }, + "Test Client ID with Buggy Redirect Uri": { + "client_secret": "TestSecret2", + "redirect_uri": " http://brentertainment.com" + }, + "Test Client ID with Multiple Redirect Uris": { + "client_secret": "TestSecret3", + "redirect_uri": "http://brentertainment.com http://morehazards.com" + }, + "Test Client ID with Redirect Uri Parts": { + "client_secret": "TestSecret4", + "redirect_uri": "http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true" + }, + "Test Some Other Client": { + "client_secret": "TestSecret3" + }, + "Test Client ID Empty Secret": { + "client_secret": "" + }, + "Test Client ID For Password Grant": { + "grant_types": "password", + "client_secret": "" + }, + "Client ID With User ID": { + "client_secret": "TestSecret", + "user_id": "brent@brentertainment.com" + }, + "oauth_test_client": { + "client_secret": "testpass", + "grant_types": "implicit password" + } + }, + "user_credentials" : { + "test-username": { + "password": "testpass" + }, + "testusername": { + "password": "testpass" + }, + "testuser": { + "password": "password", + "email": "testuser@test.com", + "email_verified": true + }, + "johndoe": { + "password": "password" + } + }, + "refresh_tokens" : { + "test-refreshtoken": { + "refresh_token": "test-refreshtoken", + "client_id": "Test Client ID", + "user_id": "test-username", + "expires": 0, + "scope": null + }, + "test-refreshtoken-with-scope": { + "refresh_token": "test-refreshtoken", + "client_id": "Test Client ID", + "user_id": "test-username", + "expires": 0, + "scope": "scope1 scope2" + } + }, + "access_tokens" : { + "accesstoken-expired": { + "access_token": "accesstoken-expired", + "client_id": "Test Client ID", + "expires": 1234567, + "scope": null + }, + "accesstoken-scope": { + "access_token": "accesstoken-scope", + "client_id": "Test Client ID", + "expires": 99999999900, + "scope": "testscope" + }, + "accesstoken-openid-connect": { + "access_token": "accesstoken-openid-connect", + "client_id": "Test Client ID", + "user_id": "testuser", + "expires": 99999999900, + "scope": "openid email" + }, + "accesstoken-malformed": { + "access_token": "accesstoken-mallformed", + "expires": 99999999900, + "scope": "testscope" + } + }, + "jwt": { + "Test Client ID": { + "key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/SxVlE8gnpFqCxgl2wjhzY7u\ncEi00s0kUg3xp7lVEvgLgYcAnHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1o\nwR0p4d9pOaJK07d01+RzoQLOIQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8\nUlvdRKBxriRnlP3qJQIDAQAB\n-----END PUBLIC KEY-----", + "subject": "testuser@ourdomain.com" + }, + "Test Client ID PHP-5.2": { + "key": "mysecretkey", + "subject": "testuser@ourdomain.com" + }, + "Missing Key Client": { + "key": null, + "subject": "testuser@ourdomain.com" + }, + "Missing Key Client PHP-5.2": { + "key": null, + "subject": "testuser@ourdomain.com" + }, + "oauth_test_client": { + "key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----", + "subject": "test_subject" + } + }, + "jti": [ + { + "issuer": "Test Client ID", + "subject": "testuser@ourdomain.com", + "audience": "http://myapp.com/oauth/auth", + "expires": 99999999900, + "jti": "used_jti" + } + ], + "supported_scopes" : [ + "scope1", + "scope2", + "scope3", + "clientscope1", + "clientscope2", + "clientscope3", + "supportedscope1", + "supportedscope2", + "supportedscope3", + "supportedscope4" + ], + "keys": { + "public_key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV\n8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN\nQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB\nAoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA\n+WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w\nC6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb\noaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56\n1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0\nCPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg\nVHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr\nuxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo\ncj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA\nHoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R\n-----END RSA PRIVATE KEY-----" + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Request/TestRequest.php b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Request/TestRequest.php new file mode 100644 index 000000000..7bbce28a4 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Request/TestRequest.php @@ -0,0 +1,61 @@ +<?php + +namespace OAuth2\Request; + +use OAuth2\Request; +use OAuth2\RequestInterface; + +/** +* +*/ +class TestRequest extends Request implements RequestInterface +{ + public $query, $request, $server, $headers; + + public function __construct() + { + $this->query = $_GET; + $this->request = $_POST; + $this->server = $_SERVER; + $this->headers = array(); + } + + 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 getAllQueryParameters() + { + return $this->query; + } + + public function setQuery(array $query) + { + $this->query = $query; + } + + public function setPost(array $params) + { + $this->server['REQUEST_METHOD'] = 'POST'; + $this->request = $params; + } + + public static function createPost(array $params = array()) + { + $request = new self(); + $request->setPost($params); + + return $request; + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/BaseTest.php b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/BaseTest.php new file mode 100755 index 000000000..f0b1274a2 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/BaseTest.php @@ -0,0 +1,36 @@ +<?php + +namespace OAuth2\Storage; + +abstract class BaseTest extends \PHPUnit_Framework_TestCase +{ + public function provideStorage() + { + $memory = Bootstrap::getInstance()->getMemoryStorage(); + $sqlite = Bootstrap::getInstance()->getSqlitePdo(); + $mysql = Bootstrap::getInstance()->getMysqlPdo(); + $postgres = Bootstrap::getInstance()->getPostgresPdo(); + $mongo = Bootstrap::getInstance()->getMongo(); + $mongoDb = Bootstrap::getInstance()->getMongoDB(); + $redis = Bootstrap::getInstance()->getRedisStorage(); + $cassandra = Bootstrap::getInstance()->getCassandraStorage(); + $dynamodb = Bootstrap::getInstance()->getDynamoDbStorage(); + $couchbase = Bootstrap::getInstance()->getCouchbase(); + + /* hack until we can fix "default_scope" dependencies in other tests */ + $memory->defaultScope = 'defaultscope1 defaultscope2'; + + return array( + array($memory), + array($sqlite), + array($mysql), + array($postgres), + array($mongo), + array($mongoDb), + array($redis), + array($cassandra), + array($dynamodb), + array($couchbase), + ); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/Bootstrap.php b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/Bootstrap.php new file mode 100755 index 000000000..3d7bdd4e9 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/Bootstrap.php @@ -0,0 +1,967 @@ +<?php + +namespace OAuth2\Storage; + +class Bootstrap +{ + const DYNAMODB_PHP_VERSION = 'none'; + + protected static $instance; + private $mysql; + private $sqlite; + private $postgres; + private $mongo; + private $mongoDb; + private $redis; + private $cassandra; + private $configDir; + private $dynamodb; + private $couchbase; + + public function __construct() + { + $this->configDir = __DIR__.'/../../../config'; + } + + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + public function getSqlitePdo() + { + if (!$this->sqlite) { + $this->removeSqliteDb(); + $pdo = new \PDO(sprintf('sqlite://%s', $this->getSqliteDir())); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $this->createSqliteDb($pdo); + + $this->sqlite = new Pdo($pdo); + } + + return $this->sqlite; + } + + public function getPostgresPdo() + { + if (!$this->postgres) { + if (in_array('pgsql', \PDO::getAvailableDrivers())) { + $this->removePostgresDb(); + $this->createPostgresDb(); + if ($pdo = $this->getPostgresDriver()) { + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $this->populatePostgresDb($pdo); + $this->postgres = new Pdo($pdo); + } + } else { + $this->postgres = new NullStorage('Postgres', 'Missing postgres PDO extension.'); + } + } + + return $this->postgres; + } + + public function getPostgresDriver() + { + try { + $pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres'); + + return $pdo; + } catch (\PDOException $e) { + $this->postgres = new NullStorage('Postgres', $e->getMessage()); + } + } + + public function getMemoryStorage() + { + return new Memory(json_decode(file_get_contents($this->configDir. '/storage.json'), true)); + } + + public function getRedisStorage() + { + if (!$this->redis) { + if (class_exists('Predis\Client')) { + $redis = new \Predis\Client(); + if ($this->testRedisConnection($redis)) { + $redis->flushdb(); + $this->redis = new Redis($redis); + $this->createRedisDb($this->redis); + } else { + $this->redis = new NullStorage('Redis', 'Unable to connect to redis server on port 6379'); + } + } else { + $this->redis = new NullStorage('Redis', 'Missing redis library. Please run "composer.phar require predis/predis:dev-master"'); + } + } + + return $this->redis; + } + + private function testRedisConnection(\Predis\Client $redis) + { + try { + $redis->connect(); + } catch (\Predis\CommunicationException $exception) { + // we were unable to connect to the redis server + return false; + } + + return true; + } + + public function getMysqlPdo() + { + if (!$this->mysql) { + $pdo = null; + try { + $pdo = new \PDO('mysql:host=localhost;', 'root'); + } catch (\PDOException $e) { + $this->mysql = new NullStorage('MySQL', 'Unable to connect to MySQL on root@localhost'); + } + + if ($pdo) { + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $this->removeMysqlDb($pdo); + $this->createMysqlDb($pdo); + + $this->mysql = new Pdo($pdo); + } + } + + return $this->mysql; + } + + public function getMongo() + { + if (!$this->mongo) { + if (class_exists('MongoClient')) { + $mongo = new \MongoClient('mongodb://localhost:27017', array('connect' => false)); + if ($this->testMongoConnection($mongo)) { + $db = $mongo->oauth2_server_php_legacy; + $this->removeMongo($db); + $this->createMongo($db); + + $this->mongo = new Mongo($db); + } else { + $this->mongo = new NullStorage('Mongo', 'Unable to connect to mongo server on "localhost:27017"'); + } + } else { + $this->mongo = new NullStorage('Mongo', 'Missing mongo php extension. Please install mongo.so'); + } + } + + return $this->mongo; + } + + public function getMongoDb() + { + if (!$this->mongoDb) { + if (class_exists('MongoDB\Client')) { + $mongoDb = new \MongoDB\Client('mongodb://localhost:27017'); + if ($this->testMongoDBConnection($mongoDb)) { + $db = $mongoDb->oauth2_server_php; + $this->removeMongoDb($db); + $this->createMongoDb($db); + + $this->mongoDb = new MongoDB($db); + } else { + $this->mongoDb = new NullStorage('MongoDB', 'Unable to connect to mongo server on "localhost:27017"'); + } + } else { + $this->mongoDb = new NullStorage('MongoDB', 'Missing MongoDB php extension. Please install mongodb.so'); + } + } + + return $this->mongoDb; + } + + private function testMongoConnection(\MongoClient $mongo) + { + try { + $mongo->connect(); + } catch (\MongoConnectionException $e) { + return false; + } + + return true; + } + + private function testMongoDBConnection(\MongoDB\Client $mongo) + { + return true; + } + + public function getCouchbase() + { + if (!$this->couchbase) { + if ($this->getEnvVar('SKIP_COUCHBASE_TESTS')) { + $this->couchbase = new NullStorage('Couchbase', 'Skipping Couchbase tests'); + } elseif (!class_exists('Couchbase')) { + $this->couchbase = new NullStorage('Couchbase', 'Missing Couchbase php extension. Please install couchbase.so'); + } else { + // round-about way to make sure couchbase is working + // this is required because it throws a "floating point exception" otherwise + $code = "new \Couchbase(array('localhost:8091'), '', '', 'auth', false);"; + $exec = sprintf('php -r "%s"', $code); + $ret = exec($exec, $test, $var); + if ($ret != 0) { + $couchbase = new \Couchbase(array('localhost:8091'), '', '', 'auth', false); + if ($this->testCouchbaseConnection($couchbase)) { + $this->clearCouchbase($couchbase); + $this->createCouchbaseDB($couchbase); + + $this->couchbase = new CouchbaseDB($couchbase); + } else { + $this->couchbase = new NullStorage('Couchbase', 'Unable to connect to Couchbase server on "localhost:8091"'); + } + } else { + $this->couchbase = new NullStorage('Couchbase', 'Error while trying to connect to Couchbase'); + } + } + } + + return $this->couchbase; + } + + private function testCouchbaseConnection(\Couchbase $couchbase) + { + try { + if (count($couchbase->getServers()) > 0) { + return true; + } + } catch (\CouchbaseException $e) { + return false; + } + + return true; + } + + public function getCassandraStorage() + { + if (!$this->cassandra) { + if (class_exists('phpcassa\ColumnFamily')) { + $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160')); + if ($this->testCassandraConnection($cassandra)) { + $this->removeCassandraDb(); + $this->cassandra = new Cassandra($cassandra); + $this->createCassandraDb($this->cassandra); + } else { + $this->cassandra = new NullStorage('Cassandra', 'Unable to connect to cassandra server on "127.0.0.1:9160"'); + } + } else { + $this->cassandra = new NullStorage('Cassandra', 'Missing cassandra library. Please run "composer.phar require thobbs/phpcassa:dev-master"'); + } + } + + return $this->cassandra; + } + + private function testCassandraConnection(\phpcassa\Connection\ConnectionPool $cassandra) + { + try { + new \phpcassa\SystemManager('localhost:9160'); + } catch (\Exception $e) { + return false; + } + + return true; + } + + private function removeCassandraDb() + { + $sys = new \phpcassa\SystemManager('localhost:9160'); + + try { + $sys->drop_keyspace('oauth2_test'); + } catch (\cassandra\InvalidRequestException $e) { + + } + } + + private function createCassandraDb(Cassandra $storage) + { + // create the cassandra keyspace and column family + $sys = new \phpcassa\SystemManager('localhost:9160'); + + $sys->create_keyspace('oauth2_test', array( + "strategy_class" => \phpcassa\Schema\StrategyClass::SIMPLE_STRATEGY, + "strategy_options" => array('replication_factor' => '1') + )); + + $sys->create_column_family('oauth2_test', 'auth'); + $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160')); + $cf = new \phpcassa\ColumnFamily($cassandra, 'auth'); + + // populate the data + $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password'); + $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000); + $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000); + + $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4'); + $storage->setScope('defaultscope1 defaultscope2', null, 'default'); + + $storage->setScope('clientscope1 clientscope2', 'Test Client ID'); + $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default'); + + $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2'); + $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default'); + + $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID'); + $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default'); + + $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2'); + $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default'); + + $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject'); + + $cf->insert("oauth_public_keys:ClientID_One", array('__data' => json_encode(array("public_key" => "client_1_public", "private_key" => "client_1_private", "encryption_algorithm" => "RS256")))); + $cf->insert("oauth_public_keys:ClientID_Two", array('__data' => json_encode(array("public_key" => "client_2_public", "private_key" => "client_2_private", "encryption_algorithm" => "RS256")))); + $cf->insert("oauth_public_keys:", array('__data' => json_encode(array("public_key" => $this->getTestPublicKey(), "private_key" => $this->getTestPrivateKey(), "encryption_algorithm" => "RS256")))); + + $cf->insert("oauth_users:testuser", array('__data' =>json_encode(array("password" => "password", "email" => "testuser@test.com", "email_verified" => true)))); + + } + + private function createSqliteDb(\PDO $pdo) + { + $this->runPdoSql($pdo); + } + + private function removeSqliteDb() + { + if (file_exists($this->getSqliteDir())) { + unlink($this->getSqliteDir()); + } + } + + private function createMysqlDb(\PDO $pdo) + { + $pdo->exec('CREATE DATABASE oauth2_server_php'); + $pdo->exec('USE oauth2_server_php'); + $this->runPdoSql($pdo); + } + + private function removeMysqlDb(\PDO $pdo) + { + $pdo->exec('DROP DATABASE IF EXISTS oauth2_server_php'); + } + + private function createPostgresDb() + { + if (!`psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'"`) { + `createuser -s -r postgres`; + } + + `createdb -O postgres oauth2_server_php`; + } + + private function populatePostgresDb(\PDO $pdo) + { + $this->runPdoSql($pdo); + } + + private function removePostgresDb() + { + if (trim(`psql -l | grep oauth2_server_php | wc -l`)) { + `dropdb oauth2_server_php`; + } + } + + public function runPdoSql(\PDO $pdo) + { + $storage = new Pdo($pdo); + foreach (explode(';', $storage->getBuildSql()) as $statement) { + $result = $pdo->exec($statement); + } + + // set up scopes + $sql = 'INSERT INTO oauth_scopes (scope) VALUES (?)'; + foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) { + $pdo->prepare($sql)->execute(array($supportedScope)); + } + + $sql = 'INSERT INTO oauth_scopes (scope, is_default) VALUES (?, ?)'; + foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) { + $pdo->prepare($sql)->execute(array($defaultScope, true)); + } + + // set up clients + $sql = 'INSERT INTO oauth_clients (client_id, client_secret, scope, grant_types) VALUES (?, ?, ?, ?)'; + $pdo->prepare($sql)->execute(array('Test Client ID', 'TestSecret', 'clientscope1 clientscope2', null)); + $pdo->prepare($sql)->execute(array('Test Client ID 2', 'TestSecret', 'clientscope1 clientscope2 clientscope3', null)); + $pdo->prepare($sql)->execute(array('Test Default Scope Client ID', 'TestSecret', 'clientscope1 clientscope2', null)); + $pdo->prepare($sql)->execute(array('oauth_test_client', 'testpass', null, 'implicit password')); + + // set up misc + $sql = 'INSERT INTO oauth_access_tokens (access_token, client_id, expires, user_id) VALUES (?, ?, ?, ?)'; + $pdo->prepare($sql)->execute(array('testtoken', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), null)); + $pdo->prepare($sql)->execute(array('accesstoken-openid-connect', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), 'testuser')); + + $sql = 'INSERT INTO oauth_authorization_codes (authorization_code, client_id, expires) VALUES (?, ?, ?)'; + $pdo->prepare($sql)->execute(array('testcode', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')))); + + $sql = 'INSERT INTO oauth_users (username, password, email, email_verified) VALUES (?, ?, ?, ?)'; + $pdo->prepare($sql)->execute(array('testuser', 'password', 'testuser@test.com', true)); + + $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)'; + $pdo->prepare($sql)->execute(array('ClientID_One', 'client_1_public', 'client_1_private', 'RS256')); + $pdo->prepare($sql)->execute(array('ClientID_Two', 'client_2_public', 'client_2_private', 'RS256')); + + $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)'; + $pdo->prepare($sql)->execute(array(null, $this->getTestPublicKey(), $this->getTestPrivateKey(), 'RS256')); + + $sql = 'INSERT INTO oauth_jwt (client_id, subject, public_key) VALUES (?, ?, ?)'; + $pdo->prepare($sql)->execute(array('oauth_test_client', 'test_subject', $this->getTestPublicKey())); + } + + public function getSqliteDir() + { + return $this->configDir. '/test.sqlite'; + } + + public function getConfigDir() + { + return $this->configDir; + } + + private function createCouchbaseDB(\Couchbase $db) + { + $db->set('oauth_clients-oauth_test_client',json_encode(array( + 'client_id' => "oauth_test_client", + 'client_secret' => "testpass", + 'redirect_uri' => "http://example.com", + 'grant_types' => 'implicit password' + ))); + + $db->set('oauth_access_tokens-testtoken',json_encode(array( + 'access_token' => "testtoken", + 'client_id' => "Some Client" + ))); + + $db->set('oauth_authorization_codes-testcode',json_encode(array( + 'access_token' => "testcode", + 'client_id' => "Some Client" + ))); + + $db->set('oauth_users-testuser',json_encode(array( + 'username' => 'testuser', + 'password' => 'password', + 'email' => 'testuser@test.com', + 'email_verified' => true, + ))); + + $db->set('oauth_jwt-oauth_test_client',json_encode(array( + 'client_id' => 'oauth_test_client', + 'key' => $this->getTestPublicKey(), + 'subject' => 'test_subject', + ))); + } + + private function clearCouchbase(\Couchbase $cb) + { + $cb->delete('oauth_authorization_codes-new-openid-code'); + $cb->delete('oauth_access_tokens-newtoken'); + $cb->delete('oauth_authorization_codes-newcode'); + $cb->delete('oauth_refresh_tokens-refreshtoken'); + } + + private function createMongo(\MongoDB $db) + { + $db->oauth_clients->insert(array( + 'client_id' => "oauth_test_client", + 'client_secret' => "testpass", + 'redirect_uri' => "http://example.com", + 'grant_types' => 'implicit password' + )); + + $db->oauth_access_tokens->insert(array( + 'access_token' => "testtoken", + 'client_id' => "Some Client" + )); + + $db->oauth_authorization_codes->insert(array( + 'authorization_code' => "testcode", + 'client_id' => "Some Client" + )); + + $db->oauth_users->insert(array( + 'username' => 'testuser', + 'password' => 'password', + 'email' => 'testuser@test.com', + 'email_verified' => true, + )); + + $db->oauth_keys->insert(array( + 'client_id' => null, + 'public_key' => $this->getTestPublicKey(), + 'private_key' => $this->getTestPrivateKey(), + 'encryption_algorithm' => 'RS256' + )); + + $db->oauth_jwt->insert(array( + 'client_id' => 'oauth_test_client', + 'key' => $this->getTestPublicKey(), + 'subject' => 'test_subject', + )); + } + + public function removeMongo(\MongoDB $db) + { + $db->drop(); + } + + private function createMongoDB(\MongoDB\Database $db) + { + $db->oauth_clients->insertOne(array( + 'client_id' => "oauth_test_client", + 'client_secret' => "testpass", + 'redirect_uri' => "http://example.com", + 'grant_types' => 'implicit password' + )); + + $db->oauth_access_tokens->insertOne(array( + 'access_token' => "testtoken", + 'client_id' => "Some Client" + )); + + $db->oauth_authorization_codes->insertOne(array( + 'authorization_code' => "testcode", + 'client_id' => "Some Client" + )); + + $db->oauth_users->insertOne(array( + 'username' => 'testuser', + 'password' => 'password', + 'email' => 'testuser@test.com', + 'email_verified' => true, + )); + + $db->oauth_keys->insertOne(array( + 'client_id' => null, + 'public_key' => $this->getTestPublicKey(), + 'private_key' => $this->getTestPrivateKey(), + 'encryption_algorithm' => 'RS256' + )); + + $db->oauth_jwt->insertOne(array( + 'client_id' => 'oauth_test_client', + 'key' => $this->getTestPublicKey(), + 'subject' => 'test_subject', + )); + } + + public function removeMongoDB(\MongoDB\Database $db) + { + $db->drop(); + } + + private function createRedisDb(Redis $storage) + { + $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password'); + $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000); + $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000); + $storage->setUser("testuser", "password"); + + $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4'); + $storage->setScope('defaultscope1 defaultscope2', null, 'default'); + + $storage->setScope('clientscope1 clientscope2', 'Test Client ID'); + $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default'); + + $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2'); + $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default'); + + $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID'); + $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default'); + + $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2'); + $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default'); + + $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject'); + } + + public function getTestPublicKey() + { + return file_get_contents(__DIR__.'/../../../config/keys/id_rsa.pub'); + } + + private function getTestPrivateKey() + { + return file_get_contents(__DIR__.'/../../../config/keys/id_rsa'); + } + + public function getDynamoDbStorage() + { + if (!$this->dynamodb) { + // only run once per travis build + if (true == $this->getEnvVar('TRAVIS')) { + if (self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) { + $this->dynamodb = new NullStorage('DynamoDb', 'Skipping for travis.ci - only run once per build'); + + return; + } + } + if (class_exists('\Aws\DynamoDb\DynamoDbClient')) { + if ($client = $this->getDynamoDbClient()) { + // travis runs a unique set of tables per build, to avoid conflict + $prefix = ''; + if ($build_id = $this->getEnvVar('TRAVIS_JOB_NUMBER')) { + $prefix = sprintf('build_%s_', $build_id); + } else { + if (!$this->deleteDynamoDb($client, $prefix, true)) { + return $this->dynamodb = new NullStorage('DynamoDb', 'Timed out while waiting for DynamoDB deletion (30 seconds)'); + } + } + $this->createDynamoDb($client, $prefix); + $this->populateDynamoDb($client, $prefix); + $config = array( + 'client_table' => $prefix.'oauth_clients', + 'access_token_table' => $prefix.'oauth_access_tokens', + 'refresh_token_table' => $prefix.'oauth_refresh_tokens', + 'code_table' => $prefix.'oauth_authorization_codes', + 'user_table' => $prefix.'oauth_users', + 'jwt_table' => $prefix.'oauth_jwt', + 'scope_table' => $prefix.'oauth_scopes', + 'public_key_table' => $prefix.'oauth_public_keys', + ); + $this->dynamodb = new DynamoDB($client, $config); + } elseif (!$this->dynamodb) { + $this->dynamodb = new NullStorage('DynamoDb', 'unable to connect to DynamoDB'); + } + } else { + $this->dynamodb = new NullStorage('DynamoDb', 'Missing DynamoDB library. Please run "composer.phar require aws/aws-sdk-php:dev-master'); + } + } + + return $this->dynamodb; + } + + private function getDynamoDbClient() + { + $config = array(); + // check for environment variables + if (($key = $this->getEnvVar('AWS_ACCESS_KEY_ID')) && ($secret = $this->getEnvVar('AWS_SECRET_KEY'))) { + $config['key'] = $key; + $config['secret'] = $secret; + } else { + // fall back on ~/.aws/credentials file + // @see http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html#credential-profiles + if (!file_exists($this->getEnvVar('HOME') . '/.aws/credentials')) { + $this->dynamodb = new NullStorage('DynamoDb', 'No aws credentials file found, and no AWS_ACCESS_KEY_ID or AWS_SECRET_KEY environment variable set'); + + return; + } + + // set profile in AWS_PROFILE environment variable, defaults to "default" + $config['profile'] = $this->getEnvVar('AWS_PROFILE', 'default'); + } + + // set region in AWS_REGION environment variable, defaults to "us-east-1" + $config['region'] = $this->getEnvVar('AWS_REGION', \Aws\Common\Enum\Region::US_EAST_1); + + return \Aws\DynamoDb\DynamoDbClient::factory($config); + } + + private function deleteDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null, $waitForDeletion = false) + { + $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users'); + $nbTables = count($tablesList); + + // Delete all table. + foreach ($tablesList as $key => $table) { + try { + $client->deleteTable(array('TableName' => $prefix.$table)); + } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { + // Table does not exist : nothing to do + } + } + + // Wait for deleting + if ($waitForDeletion) { + $retries = 5; + $nbTableDeleted = 0; + while ($nbTableDeleted != $nbTables) { + $nbTableDeleted = 0; + foreach ($tablesList as $key => $table) { + try { + $result = $client->describeTable(array('TableName' => $prefix.$table)); + } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { + // Table does not exist : nothing to do + $nbTableDeleted++; + } + } + if ($nbTableDeleted != $nbTables) { + if ($retries < 0) { + // we are tired of waiting + return false; + } + sleep(5); + echo "Sleeping 5 seconds for DynamoDB ($retries more retries)...\n"; + $retries--; + } + } + } + + return true; + } + + private function createDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null) + { + $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users'); + $nbTables = count($tablesList); + $client->createTable(array( + 'TableName' => $prefix.'oauth_access_tokens', + 'AttributeDefinitions' => array( + array('AttributeName' => 'access_token','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'access_token','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_authorization_codes', + 'AttributeDefinitions' => array( + array('AttributeName' => 'authorization_code','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'authorization_code','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_clients', + 'AttributeDefinitions' => array( + array('AttributeName' => 'client_id','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_jwt', + 'AttributeDefinitions' => array( + array('AttributeName' => 'client_id','AttributeType' => 'S'), + array('AttributeName' => 'subject','AttributeType' => 'S') + ), + 'KeySchema' => array( + array('AttributeName' => 'client_id','KeyType' => 'HASH'), + array('AttributeName' => 'subject','KeyType' => 'RANGE') + ), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_public_keys', + 'AttributeDefinitions' => array( + array('AttributeName' => 'client_id','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_refresh_tokens', + 'AttributeDefinitions' => array( + array('AttributeName' => 'refresh_token','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'refresh_token','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_scopes', + 'AttributeDefinitions' => array( + array('AttributeName' => 'scope','AttributeType' => 'S'), + array('AttributeName' => 'is_default','AttributeType' => 'S') + ), + 'KeySchema' => array(array('AttributeName' => 'scope','KeyType' => 'HASH')), + 'GlobalSecondaryIndexes' => array( + array( + 'IndexName' => 'is_default-index', + 'KeySchema' => array(array('AttributeName' => 'is_default', 'KeyType' => 'HASH')), + 'Projection' => array('ProjectionType' => 'ALL'), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + ), + ), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + $client->createTable(array( + 'TableName' => $prefix.'oauth_users', + 'AttributeDefinitions' => array(array('AttributeName' => 'username','AttributeType' => 'S')), + 'KeySchema' => array(array('AttributeName' => 'username','KeyType' => 'HASH')), + 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) + )); + + // Wait for creation + $nbTableCreated = 0; + while ($nbTableCreated != $nbTables) { + $nbTableCreated = 0; + foreach ($tablesList as $key => $table) { + try { + $result = $client->describeTable(array('TableName' => $prefix.$table)); + if ($result['Table']['TableStatus'] == 'ACTIVE') { + $nbTableCreated++; + } + } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { + // Table does not exist : nothing to do + $nbTableCreated++; + } + } + if ($nbTableCreated != $nbTables) { + sleep(1); + } + } + } + + private function populateDynamoDb($client, $prefix = null) + { + // set up scopes + foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) { + $client->putItem(array( + 'TableName' => $prefix.'oauth_scopes', + 'Item' => array('scope' => array('S' => $supportedScope)) + )); + } + + foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) { + $client->putItem(array( + 'TableName' => $prefix.'oauth_scopes', + 'Item' => array('scope' => array('S' => $defaultScope), 'is_default' => array('S' => "true")) + )); + } + + $client->putItem(array( + 'TableName' => $prefix.'oauth_clients', + 'Item' => array( + 'client_id' => array('S' => 'Test Client ID'), + 'client_secret' => array('S' => 'TestSecret'), + 'scope' => array('S' => 'clientscope1 clientscope2') + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_clients', + 'Item' => array( + 'client_id' => array('S' => 'Test Client ID 2'), + 'client_secret' => array('S' => 'TestSecret'), + 'scope' => array('S' => 'clientscope1 clientscope2 clientscope3') + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_clients', + 'Item' => array( + 'client_id' => array('S' => 'Test Default Scope Client ID'), + 'client_secret' => array('S' => 'TestSecret'), + 'scope' => array('S' => 'clientscope1 clientscope2') + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_clients', + 'Item' => array( + 'client_id' => array('S' => 'oauth_test_client'), + 'client_secret' => array('S' => 'testpass'), + 'grant_types' => array('S' => 'implicit password') + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_access_tokens', + 'Item' => array( + 'access_token' => array('S' => 'testtoken'), + 'client_id' => array('S' => 'Some Client'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_access_tokens', + 'Item' => array( + 'access_token' => array('S' => 'accesstoken-openid-connect'), + 'client_id' => array('S' => 'Some Client'), + 'user_id' => array('S' => 'testuser'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_authorization_codes', + 'Item' => array( + 'authorization_code' => array('S' => 'testcode'), + 'client_id' => array('S' => 'Some Client'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_users', + 'Item' => array( + 'username' => array('S' => 'testuser'), + 'password' => array('S' => 'password'), + 'email' => array('S' => 'testuser@test.com'), + 'email_verified' => array('S' => 'true'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_public_keys', + 'Item' => array( + 'client_id' => array('S' => 'ClientID_One'), + 'public_key' => array('S' => 'client_1_public'), + 'private_key' => array('S' => 'client_1_private'), + 'encryption_algorithm' => array('S' => 'RS256'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_public_keys', + 'Item' => array( + 'client_id' => array('S' => 'ClientID_Two'), + 'public_key' => array('S' => 'client_2_public'), + 'private_key' => array('S' => 'client_2_private'), + 'encryption_algorithm' => array('S' => 'RS256'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_public_keys', + 'Item' => array( + 'client_id' => array('S' => '0'), + 'public_key' => array('S' => $this->getTestPublicKey()), + 'private_key' => array('S' => $this->getTestPrivateKey()), + 'encryption_algorithm' => array('S' => 'RS256'), + ) + )); + + $client->putItem(array( + 'TableName' => $prefix.'oauth_jwt', + 'Item' => array( + 'client_id' => array('S' => 'oauth_test_client'), + 'subject' => array('S' => 'test_subject'), + 'public_key' => array('S' => $this->getTestPublicKey()), + ) + )); + } + + public function cleanupTravisDynamoDb($prefix = null) + { + if (is_null($prefix)) { + // skip this when not applicable + if (!$this->getEnvVar('TRAVIS') || self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) { + return; + } + + $prefix = sprintf('build_%s_', $this->getEnvVar('TRAVIS_JOB_NUMBER')); + } + + $client = $this->getDynamoDbClient(); + $this->deleteDynamoDb($client, $prefix); + } + + private function getEnvVar($var, $default = null) + { + return isset($_SERVER[$var]) ? $_SERVER[$var] : (getenv($var) ?: $default); + } +} diff --git a/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/NullStorage.php b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/NullStorage.php new file mode 100644 index 000000000..6caa62068 --- /dev/null +++ b/vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/NullStorage.php @@ -0,0 +1,32 @@ +<?php + +namespace OAuth2\Storage; + +/** +* +*/ +class NullStorage extends Memory +{ + private $name; + private $description; + + public function __construct($name, $description = null) + { + $this->name = $name; + $this->description = $description; + } + + public function __toString() + { + return $this->name; + } + + public function getMessage() + { + if ($this->description) { + return $this->description; + } + + return $this->name; + } +} diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index 4626994fd..ff6ecfb82 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -53,9 +53,8 @@ class ClassLoader private $useIncludePath = false; private $classMap = array(); + private $classMapAuthoritative = false; - private $missingClasses = array(); - private $apcuPrefix; public function getPrefixes() { @@ -273,26 +272,6 @@ class ClassLoader } /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not @@ -334,34 +313,29 @@ class ClassLoader */ public function findFile($class) { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + if ($this->classMapAuthoritative) { return false; } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { + if ($file === null && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { + if ($file === null) { // Remember that this class does not exist. - $this->missingClasses[$class] = true; + return $this->classMap[$class] = false; } return $file; @@ -425,8 +399,6 @@ class ClassLoader if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } - - return false; } } diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE index 1a2812488..ee274f1d3 100644 --- a/vendor/composer/LICENSE +++ b/vendor/composer/LICENSE @@ -1,21 +1,433 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Composer +Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be> +Source: https://github.com/composer/composer -Copyright (c) 2016 Nils Adermann, Jordi Boggiano +Files: * +Copyright: 2016, Nils Adermann <naderman@naderman.de> + 2016, Jordi Boggiano <j.boggiano@seld.be> +License: Expat -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: +Files: res/cacert.pem +Copyright: 2015, Mozilla Foundation +License: MPL-2.0 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Files: src/Composer/Util/RemoteFilesystem.php + src/Composer/Util/TlsHelper.php +Copyright: 2016, Nils Adermann <naderman@naderman.de> + 2016, Jordi Boggiano <j.boggiano@seld.be> + 2013, Evan Coury <me@evancoury.com> +License: Expat and BSD-2-Clause -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. +License: BSD-2-Clause + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + . + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +License: Expat + 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. + +License: MPL-2.0 + 1. Definitions + -------------- + . + 1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + . + 1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + . + 1.3. "Contribution" + means Covered Software of a particular Contributor. + . + 1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + . + 1.5. "Incompatible With Secondary Licenses" + means + . + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + . + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + . + 1.6. "Executable Form" + means any form of the work other than Source Code Form. + . + 1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + . + 1.8. "License" + means this document. + . + 1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + . + 1.10. "Modifications" + means any of the following: + . + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + . + (b) any new file in Source Code Form that contains any Covered + Software. + . + 1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + . + 1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + . + 1.13. "Source Code Form" + means the form of the work preferred for making modifications. + . + 1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + . + 2. License Grants and Conditions + -------------------------------- + . + 2.1. Grants + . + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + . + (a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + . + (b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + . + 2.2. Effective Date + . + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + . + 2.3. Limitations on Grant Scope + . + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + . + (a) for any code that a Contributor has removed from Covered Software; + or + . + (b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + . + (c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + . + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + . + 2.4. Subsequent Licenses + . + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + . + 2.5. Representation + . + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights + to grant the rights to its Contributions conveyed by this License. + . + 2.6. Fair Use + . + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + . + 2.7. Conditions + . + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted + in Section 2.1. + . + 3. Responsibilities + ------------------- + . + 3.1. Distribution of Source Form + . + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + . + 3.2. Distribution of Executable Form + . + If You distribute Covered Software in Executable Form then: + . + (a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + . + (b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + . + 3.3. Distribution of a Larger Work + . + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + . + 3.4. Notices + . + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, + or limitations of liability) contained within the Source Code Form of + the Covered Software, except that You may alter any license notices to + the extent required to remedy known factual inaccuracies. + . + 3.5. Application of Additional Terms + . + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + . + 4. Inability to Comply Due to Statute or Regulation + --------------------------------------------------- + . + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Software due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description must + be placed in a text file included with all distributions of the Covered + Software under this License. Except to the extent prohibited by statute + or regulation, such description must be sufficiently detailed for a + recipient of ordinary skill to be able to understand it. + . + 5. Termination + -------------- + . + 5.1. The rights granted under this License will terminate automatically + if You fail to comply with any of its terms. However, if You become + compliant, then the rights granted under this License from a particular + Contributor are reinstated (a) provisionally, unless and until such + Contributor explicitly and finally terminates Your grants, and (b) on an + ongoing basis, if such Contributor fails to notify You of the + non-compliance by some reasonable means prior to 60 days after You have + come back into compliance. Moreover, Your grants from a particular + Contributor are reinstated on an ongoing basis if such Contributor + notifies You of the non-compliance by some reasonable means, this is the + first time You have received notice of non-compliance with this License + from such Contributor, and You become compliant prior to 30 days after + Your receipt of the notice. + . + 5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + . + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all + end user license agreements (excluding distributors and resellers) which + have been validly granted by You or Your distributors under this License + prior to termination shall survive termination. + . + ************************************************************************ + * * + * 6. Disclaimer of Warranty * + * ------------------------- * + * * + * Covered Software is provided under this License on an "as is" * + * basis, without warranty of any kind, either expressed, implied, or * + * statutory, including, without limitation, warranties that the * + * Covered Software is free of defects, merchantable, fit for a * + * particular purpose or non-infringing. The entire risk as to the * + * quality and performance of the Covered Software is with You. * + * Should any Covered Software prove defective in any respect, You * + * (not any Contributor) assume the cost of any necessary servicing, * + * repair, or correction. This disclaimer of warranty constitutes an * + * essential part of this License. No use of any Covered Software is * + * authorized under this License except under this disclaimer. * + * * + ************************************************************************ + . + ************************************************************************ + * * + * 7. Limitation of Liability * + * -------------------------- * + * * + * Under no circumstances and under no legal theory, whether tort * + * (including negligence), contract, or otherwise, shall any * + * Contributor, or anyone who distributes Covered Software as * + * permitted above, be liable to You for any direct, indirect, * + * special, incidental, or consequential damages of any character * + * including, without limitation, damages for lost profits, loss of * + * goodwill, work stoppage, computer failure or malfunction, or any * + * and all other commercial damages or losses, even if such party * + * shall have been informed of the possibility of such damages. This * + * limitation of liability shall not apply to liability for death or * + * personal injury resulting from such party's negligence to the * + * extent applicable law prohibits such limitation. Some * + * jurisdictions do not allow the exclusion or limitation of * + * incidental or consequential damages, so this exclusion and * + * limitation may not apply to You. * + * * + ************************************************************************ + . + 8. Litigation + ------------- + . + Any litigation relating to this License may be brought only in the + courts of a jurisdiction where the defendant maintains its principal + place of business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. + Nothing in this Section shall prevent a party's ability to bring + cross-claims or counter-claims. + . + 9. Miscellaneous + ---------------- + . + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides + that the language of a contract shall be construed against the drafter + shall not be used to construe this License against a Contributor. + . + 10. Versions of the License + --------------------------- + . + 10.1. New Versions + . + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + . + 10.2. Effect of New Versions + . + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + . + 10.3. Modified Versions + . + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + . + 10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses + . + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + . + Exhibit A - Source Code Form License Notice + ------------------------------------------- + . + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + . + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to look + for such a notice. + . + You may add additional accurate notices of copyright ownership. + . + Exhibit B - "Incompatible With Secondary Licenses" Notice + --------------------------------------------------------- + . + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 28ef0d2bf..7a91153b0 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,620 +6,4 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - 'Hubzilla\\Import\\Import' => $baseDir . '/include/Import/Importer.php', - 'Markdownify\\Converter' => $vendorDir . '/pixel418/markdownify/src/Converter.php', - 'Markdownify\\ConverterExtra' => $vendorDir . '/pixel418/markdownify/src/ConverterExtra.php', - 'Markdownify\\Parser' => $vendorDir . '/pixel418/markdownify/src/Parser.php', - 'Michelf\\Markdown' => $vendorDir . '/michelf/php-markdown/Michelf/Markdown.php', - 'Michelf\\MarkdownExtra' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownExtra.php', - 'Michelf\\MarkdownInterface' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownInterface.php', - 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php', - 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php', - 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php', - 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php', - 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php', - 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php', - 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php', - 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php', - 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', - 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', - 'Sabre\\CalDAV\\Backend\\AbstractBackend' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php', - 'Sabre\\CalDAV\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/BackendInterface.php', - 'Sabre\\CalDAV\\Backend\\NotificationSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php', - 'Sabre\\CalDAV\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/PDO.php', - 'Sabre\\CalDAV\\Backend\\SchedulingSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/SchedulingSupport.php', - 'Sabre\\CalDAV\\Backend\\SharingSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/SharingSupport.php', - 'Sabre\\CalDAV\\Backend\\SimplePDO' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/SimplePDO.php', - 'Sabre\\CalDAV\\Backend\\SubscriptionSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php', - 'Sabre\\CalDAV\\Backend\\SyncSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/SyncSupport.php', - 'Sabre\\CalDAV\\Calendar' => $vendorDir . '/sabre/dav/lib/CalDAV/Calendar.php', - 'Sabre\\CalDAV\\CalendarHome' => $vendorDir . '/sabre/dav/lib/CalDAV/CalendarHome.php', - 'Sabre\\CalDAV\\CalendarObject' => $vendorDir . '/sabre/dav/lib/CalDAV/CalendarObject.php', - 'Sabre\\CalDAV\\CalendarQueryValidator' => $vendorDir . '/sabre/dav/lib/CalDAV/CalendarQueryValidator.php', - 'Sabre\\CalDAV\\CalendarRoot' => $vendorDir . '/sabre/dav/lib/CalDAV/CalendarRoot.php', - 'Sabre\\CalDAV\\Exception\\InvalidComponentType' => $vendorDir . '/sabre/dav/lib/CalDAV/Exception/InvalidComponentType.php', - 'Sabre\\CalDAV\\ICSExportPlugin' => $vendorDir . '/sabre/dav/lib/CalDAV/ICSExportPlugin.php', - 'Sabre\\CalDAV\\ICalendar' => $vendorDir . '/sabre/dav/lib/CalDAV/ICalendar.php', - 'Sabre\\CalDAV\\ICalendarObject' => $vendorDir . '/sabre/dav/lib/CalDAV/ICalendarObject.php', - 'Sabre\\CalDAV\\ICalendarObjectContainer' => $vendorDir . '/sabre/dav/lib/CalDAV/ICalendarObjectContainer.php', - 'Sabre\\CalDAV\\ISharedCalendar' => $vendorDir . '/sabre/dav/lib/CalDAV/ISharedCalendar.php', - 'Sabre\\CalDAV\\Notifications\\Collection' => $vendorDir . '/sabre/dav/lib/CalDAV/Notifications/Collection.php', - 'Sabre\\CalDAV\\Notifications\\ICollection' => $vendorDir . '/sabre/dav/lib/CalDAV/Notifications/ICollection.php', - 'Sabre\\CalDAV\\Notifications\\INode' => $vendorDir . '/sabre/dav/lib/CalDAV/Notifications/INode.php', - 'Sabre\\CalDAV\\Notifications\\Node' => $vendorDir . '/sabre/dav/lib/CalDAV/Notifications/Node.php', - 'Sabre\\CalDAV\\Notifications\\Plugin' => $vendorDir . '/sabre/dav/lib/CalDAV/Notifications/Plugin.php', - 'Sabre\\CalDAV\\Plugin' => $vendorDir . '/sabre/dav/lib/CalDAV/Plugin.php', - 'Sabre\\CalDAV\\Principal\\Collection' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/Collection.php', - 'Sabre\\CalDAV\\Principal\\IProxyRead' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/IProxyRead.php', - 'Sabre\\CalDAV\\Principal\\IProxyWrite' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/IProxyWrite.php', - 'Sabre\\CalDAV\\Principal\\ProxyRead' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/ProxyRead.php', - 'Sabre\\CalDAV\\Principal\\ProxyWrite' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/ProxyWrite.php', - 'Sabre\\CalDAV\\Principal\\User' => $vendorDir . '/sabre/dav/lib/CalDAV/Principal/User.php', - 'Sabre\\CalDAV\\Schedule\\IInbox' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/IInbox.php', - 'Sabre\\CalDAV\\Schedule\\IMipPlugin' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php', - 'Sabre\\CalDAV\\Schedule\\IOutbox' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/IOutbox.php', - 'Sabre\\CalDAV\\Schedule\\ISchedulingObject' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/ISchedulingObject.php', - 'Sabre\\CalDAV\\Schedule\\Inbox' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/Inbox.php', - 'Sabre\\CalDAV\\Schedule\\Outbox' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/Outbox.php', - 'Sabre\\CalDAV\\Schedule\\Plugin' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/Plugin.php', - 'Sabre\\CalDAV\\Schedule\\SchedulingObject' => $vendorDir . '/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php', - 'Sabre\\CalDAV\\SharedCalendar' => $vendorDir . '/sabre/dav/lib/CalDAV/SharedCalendar.php', - 'Sabre\\CalDAV\\SharingPlugin' => $vendorDir . '/sabre/dav/lib/CalDAV/SharingPlugin.php', - 'Sabre\\CalDAV\\Subscriptions\\ISubscription' => $vendorDir . '/sabre/dav/lib/CalDAV/Subscriptions/ISubscription.php', - 'Sabre\\CalDAV\\Subscriptions\\Plugin' => $vendorDir . '/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php', - 'Sabre\\CalDAV\\Subscriptions\\Subscription' => $vendorDir . '/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php', - 'Sabre\\CalDAV\\Xml\\Filter\\CalendarData' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php', - 'Sabre\\CalDAV\\Xml\\Filter\\CompFilter' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php', - 'Sabre\\CalDAV\\Xml\\Filter\\ParamFilter' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php', - 'Sabre\\CalDAV\\Xml\\Filter\\PropFilter' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php', - 'Sabre\\CalDAV\\Xml\\Notification\\Invite' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php', - 'Sabre\\CalDAV\\Xml\\Notification\\InviteReply' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php', - 'Sabre\\CalDAV\\Xml\\Notification\\NotificationInterface' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Notification/NotificationInterface.php', - 'Sabre\\CalDAV\\Xml\\Notification\\SystemStatus' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Notification/SystemStatus.php', - 'Sabre\\CalDAV\\Xml\\Property\\AllowedSharingModes' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/AllowedSharingModes.php', - 'Sabre\\CalDAV\\Xml\\Property\\EmailAddressSet' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/EmailAddressSet.php', - 'Sabre\\CalDAV\\Xml\\Property\\Invite' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/Invite.php', - 'Sabre\\CalDAV\\Xml\\Property\\ScheduleCalendarTransp' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php', - 'Sabre\\CalDAV\\Xml\\Property\\SupportedCalendarComponentSet' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarComponentSet.php', - 'Sabre\\CalDAV\\Xml\\Property\\SupportedCalendarData' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarData.php', - 'Sabre\\CalDAV\\Xml\\Property\\SupportedCollationSet' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Property/SupportedCollationSet.php', - 'Sabre\\CalDAV\\Xml\\Request\\CalendarMultiGetReport' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/CalendarMultiGetReport.php', - 'Sabre\\CalDAV\\Xml\\Request\\CalendarQueryReport' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/CalendarQueryReport.php', - 'Sabre\\CalDAV\\Xml\\Request\\FreeBusyQueryReport' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/FreeBusyQueryReport.php', - 'Sabre\\CalDAV\\Xml\\Request\\InviteReply' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php', - 'Sabre\\CalDAV\\Xml\\Request\\MkCalendar' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/MkCalendar.php', - 'Sabre\\CalDAV\\Xml\\Request\\Share' => $vendorDir . '/sabre/dav/lib/CalDAV/Xml/Request/Share.php', - 'Sabre\\CardDAV\\AddressBook' => $vendorDir . '/sabre/dav/lib/CardDAV/AddressBook.php', - 'Sabre\\CardDAV\\AddressBookHome' => $vendorDir . '/sabre/dav/lib/CardDAV/AddressBookHome.php', - 'Sabre\\CardDAV\\AddressBookRoot' => $vendorDir . '/sabre/dav/lib/CardDAV/AddressBookRoot.php', - 'Sabre\\CardDAV\\Backend\\AbstractBackend' => $vendorDir . '/sabre/dav/lib/CardDAV/Backend/AbstractBackend.php', - 'Sabre\\CardDAV\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/CardDAV/Backend/BackendInterface.php', - 'Sabre\\CardDAV\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/CardDAV/Backend/PDO.php', - 'Sabre\\CardDAV\\Backend\\SyncSupport' => $vendorDir . '/sabre/dav/lib/CardDAV/Backend/SyncSupport.php', - 'Sabre\\CardDAV\\Card' => $vendorDir . '/sabre/dav/lib/CardDAV/Card.php', - 'Sabre\\CardDAV\\IAddressBook' => $vendorDir . '/sabre/dav/lib/CardDAV/IAddressBook.php', - 'Sabre\\CardDAV\\ICard' => $vendorDir . '/sabre/dav/lib/CardDAV/ICard.php', - 'Sabre\\CardDAV\\IDirectory' => $vendorDir . '/sabre/dav/lib/CardDAV/IDirectory.php', - 'Sabre\\CardDAV\\Plugin' => $vendorDir . '/sabre/dav/lib/CardDAV/Plugin.php', - 'Sabre\\CardDAV\\VCFExportPlugin' => $vendorDir . '/sabre/dav/lib/CardDAV/VCFExportPlugin.php', - 'Sabre\\CardDAV\\Xml\\Filter\\AddressData' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Filter/AddressData.php', - 'Sabre\\CardDAV\\Xml\\Filter\\ParamFilter' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Filter/ParamFilter.php', - 'Sabre\\CardDAV\\Xml\\Filter\\PropFilter' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Filter/PropFilter.php', - 'Sabre\\CardDAV\\Xml\\Property\\SupportedAddressData' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Property/SupportedAddressData.php', - 'Sabre\\CardDAV\\Xml\\Property\\SupportedCollationSet' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Property/SupportedCollationSet.php', - 'Sabre\\CardDAV\\Xml\\Request\\AddressBookMultiGetReport' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Request/AddressBookMultiGetReport.php', - 'Sabre\\CardDAV\\Xml\\Request\\AddressBookQueryReport' => $vendorDir . '/sabre/dav/lib/CardDAV/Xml/Request/AddressBookQueryReport.php', - 'Sabre\\DAVACL\\ACLTrait' => $vendorDir . '/sabre/dav/lib/DAVACL/ACLTrait.php', - 'Sabre\\DAVACL\\AbstractPrincipalCollection' => $vendorDir . '/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php', - 'Sabre\\DAVACL\\Exception\\AceConflict' => $vendorDir . '/sabre/dav/lib/DAVACL/Exception/AceConflict.php', - 'Sabre\\DAVACL\\Exception\\NeedPrivileges' => $vendorDir . '/sabre/dav/lib/DAVACL/Exception/NeedPrivileges.php', - 'Sabre\\DAVACL\\Exception\\NoAbstract' => $vendorDir . '/sabre/dav/lib/DAVACL/Exception/NoAbstract.php', - 'Sabre\\DAVACL\\Exception\\NotRecognizedPrincipal' => $vendorDir . '/sabre/dav/lib/DAVACL/Exception/NotRecognizedPrincipal.php', - 'Sabre\\DAVACL\\Exception\\NotSupportedPrivilege' => $vendorDir . '/sabre/dav/lib/DAVACL/Exception/NotSupportedPrivilege.php', - 'Sabre\\DAVACL\\FS\\Collection' => $vendorDir . '/sabre/dav/lib/DAVACL/FS/Collection.php', - 'Sabre\\DAVACL\\FS\\File' => $vendorDir . '/sabre/dav/lib/DAVACL/FS/File.php', - 'Sabre\\DAVACL\\FS\\HomeCollection' => $vendorDir . '/sabre/dav/lib/DAVACL/FS/HomeCollection.php', - 'Sabre\\DAVACL\\IACL' => $vendorDir . '/sabre/dav/lib/DAVACL/IACL.php', - 'Sabre\\DAVACL\\IPrincipal' => $vendorDir . '/sabre/dav/lib/DAVACL/IPrincipal.php', - 'Sabre\\DAVACL\\IPrincipalCollection' => $vendorDir . '/sabre/dav/lib/DAVACL/IPrincipalCollection.php', - 'Sabre\\DAVACL\\Plugin' => $vendorDir . '/sabre/dav/lib/DAVACL/Plugin.php', - 'Sabre\\DAVACL\\Principal' => $vendorDir . '/sabre/dav/lib/DAVACL/Principal.php', - 'Sabre\\DAVACL\\PrincipalBackend\\AbstractBackend' => $vendorDir . '/sabre/dav/lib/DAVACL/PrincipalBackend/AbstractBackend.php', - 'Sabre\\DAVACL\\PrincipalBackend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/DAVACL/PrincipalBackend/BackendInterface.php', - 'Sabre\\DAVACL\\PrincipalBackend\\CreatePrincipalSupport' => $vendorDir . '/sabre/dav/lib/DAVACL/PrincipalBackend/CreatePrincipalSupport.php', - 'Sabre\\DAVACL\\PrincipalBackend\\PDO' => $vendorDir . '/sabre/dav/lib/DAVACL/PrincipalBackend/PDO.php', - 'Sabre\\DAVACL\\PrincipalCollection' => $vendorDir . '/sabre/dav/lib/DAVACL/PrincipalCollection.php', - 'Sabre\\DAVACL\\Xml\\Property\\Acl' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Property/Acl.php', - 'Sabre\\DAVACL\\Xml\\Property\\AclRestrictions' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Property/AclRestrictions.php', - 'Sabre\\DAVACL\\Xml\\Property\\CurrentUserPrivilegeSet' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Property/CurrentUserPrivilegeSet.php', - 'Sabre\\DAVACL\\Xml\\Property\\Principal' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Property/Principal.php', - 'Sabre\\DAVACL\\Xml\\Property\\SupportedPrivilegeSet' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Property/SupportedPrivilegeSet.php', - 'Sabre\\DAVACL\\Xml\\Request\\AclPrincipalPropSetReport' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Request/AclPrincipalPropSetReport.php', - 'Sabre\\DAVACL\\Xml\\Request\\ExpandPropertyReport' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Request/ExpandPropertyReport.php', - 'Sabre\\DAVACL\\Xml\\Request\\PrincipalMatchReport' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Request/PrincipalMatchReport.php', - 'Sabre\\DAVACL\\Xml\\Request\\PrincipalPropertySearchReport' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Request/PrincipalPropertySearchReport.php', - 'Sabre\\DAVACL\\Xml\\Request\\PrincipalSearchPropertySetReport' => $vendorDir . '/sabre/dav/lib/DAVACL/Xml/Request/PrincipalSearchPropertySetReport.php', - 'Sabre\\DAV\\Auth\\Backend\\AbstractBasic' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/AbstractBasic.php', - 'Sabre\\DAV\\Auth\\Backend\\AbstractBearer' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/AbstractBearer.php', - 'Sabre\\DAV\\Auth\\Backend\\AbstractDigest' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/AbstractDigest.php', - 'Sabre\\DAV\\Auth\\Backend\\Apache' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/Apache.php', - 'Sabre\\DAV\\Auth\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/BackendInterface.php', - 'Sabre\\DAV\\Auth\\Backend\\BasicCallBack' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/BasicCallBack.php', - 'Sabre\\DAV\\Auth\\Backend\\File' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/File.php', - 'Sabre\\DAV\\Auth\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/PDO.php', - 'Sabre\\DAV\\Auth\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Plugin.php', - 'Sabre\\DAV\\Browser\\GuessContentType' => $vendorDir . '/sabre/dav/lib/DAV/Browser/GuessContentType.php', - 'Sabre\\DAV\\Browser\\HtmlOutput' => $vendorDir . '/sabre/dav/lib/DAV/Browser/HtmlOutput.php', - 'Sabre\\DAV\\Browser\\HtmlOutputHelper' => $vendorDir . '/sabre/dav/lib/DAV/Browser/HtmlOutputHelper.php', - 'Sabre\\DAV\\Browser\\MapGetToPropFind' => $vendorDir . '/sabre/dav/lib/DAV/Browser/MapGetToPropFind.php', - 'Sabre\\DAV\\Browser\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Browser/Plugin.php', - 'Sabre\\DAV\\Browser\\PropFindAll' => $vendorDir . '/sabre/dav/lib/DAV/Browser/PropFindAll.php', - 'Sabre\\DAV\\Client' => $vendorDir . '/sabre/dav/lib/DAV/Client.php', - 'Sabre\\DAV\\Collection' => $vendorDir . '/sabre/dav/lib/DAV/Collection.php', - 'Sabre\\DAV\\CorePlugin' => $vendorDir . '/sabre/dav/lib/DAV/CorePlugin.php', - 'Sabre\\DAV\\Exception' => $vendorDir . '/sabre/dav/lib/DAV/Exception.php', - 'Sabre\\DAV\\Exception\\BadRequest' => $vendorDir . '/sabre/dav/lib/DAV/Exception/BadRequest.php', - 'Sabre\\DAV\\Exception\\Conflict' => $vendorDir . '/sabre/dav/lib/DAV/Exception/Conflict.php', - 'Sabre\\DAV\\Exception\\ConflictingLock' => $vendorDir . '/sabre/dav/lib/DAV/Exception/ConflictingLock.php', - 'Sabre\\DAV\\Exception\\Forbidden' => $vendorDir . '/sabre/dav/lib/DAV/Exception/Forbidden.php', - 'Sabre\\DAV\\Exception\\InsufficientStorage' => $vendorDir . '/sabre/dav/lib/DAV/Exception/InsufficientStorage.php', - 'Sabre\\DAV\\Exception\\InvalidResourceType' => $vendorDir . '/sabre/dav/lib/DAV/Exception/InvalidResourceType.php', - 'Sabre\\DAV\\Exception\\InvalidSyncToken' => $vendorDir . '/sabre/dav/lib/DAV/Exception/InvalidSyncToken.php', - 'Sabre\\DAV\\Exception\\LengthRequired' => $vendorDir . '/sabre/dav/lib/DAV/Exception/LengthRequired.php', - 'Sabre\\DAV\\Exception\\LockTokenMatchesRequestUri' => $vendorDir . '/sabre/dav/lib/DAV/Exception/LockTokenMatchesRequestUri.php', - 'Sabre\\DAV\\Exception\\Locked' => $vendorDir . '/sabre/dav/lib/DAV/Exception/Locked.php', - 'Sabre\\DAV\\Exception\\MethodNotAllowed' => $vendorDir . '/sabre/dav/lib/DAV/Exception/MethodNotAllowed.php', - 'Sabre\\DAV\\Exception\\NotAuthenticated' => $vendorDir . '/sabre/dav/lib/DAV/Exception/NotAuthenticated.php', - 'Sabre\\DAV\\Exception\\NotFound' => $vendorDir . '/sabre/dav/lib/DAV/Exception/NotFound.php', - 'Sabre\\DAV\\Exception\\NotImplemented' => $vendorDir . '/sabre/dav/lib/DAV/Exception/NotImplemented.php', - 'Sabre\\DAV\\Exception\\PaymentRequired' => $vendorDir . '/sabre/dav/lib/DAV/Exception/PaymentRequired.php', - 'Sabre\\DAV\\Exception\\PreconditionFailed' => $vendorDir . '/sabre/dav/lib/DAV/Exception/PreconditionFailed.php', - 'Sabre\\DAV\\Exception\\ReportNotSupported' => $vendorDir . '/sabre/dav/lib/DAV/Exception/ReportNotSupported.php', - 'Sabre\\DAV\\Exception\\RequestedRangeNotSatisfiable' => $vendorDir . '/sabre/dav/lib/DAV/Exception/RequestedRangeNotSatisfiable.php', - 'Sabre\\DAV\\Exception\\ServiceUnavailable' => $vendorDir . '/sabre/dav/lib/DAV/Exception/ServiceUnavailable.php', - 'Sabre\\DAV\\Exception\\TooManyMatches' => $vendorDir . '/sabre/dav/lib/DAV/Exception/TooManyMatches.php', - 'Sabre\\DAV\\Exception\\UnsupportedMediaType' => $vendorDir . '/sabre/dav/lib/DAV/Exception/UnsupportedMediaType.php', - 'Sabre\\DAV\\FSExt\\Directory' => $vendorDir . '/sabre/dav/lib/DAV/FSExt/Directory.php', - 'Sabre\\DAV\\FSExt\\File' => $vendorDir . '/sabre/dav/lib/DAV/FSExt/File.php', - 'Sabre\\DAV\\FS\\Directory' => $vendorDir . '/sabre/dav/lib/DAV/FS/Directory.php', - 'Sabre\\DAV\\FS\\File' => $vendorDir . '/sabre/dav/lib/DAV/FS/File.php', - 'Sabre\\DAV\\FS\\Node' => $vendorDir . '/sabre/dav/lib/DAV/FS/Node.php', - 'Sabre\\DAV\\File' => $vendorDir . '/sabre/dav/lib/DAV/File.php', - 'Sabre\\DAV\\ICollection' => $vendorDir . '/sabre/dav/lib/DAV/ICollection.php', - 'Sabre\\DAV\\IExtendedCollection' => $vendorDir . '/sabre/dav/lib/DAV/IExtendedCollection.php', - 'Sabre\\DAV\\IFile' => $vendorDir . '/sabre/dav/lib/DAV/IFile.php', - 'Sabre\\DAV\\IMoveTarget' => $vendorDir . '/sabre/dav/lib/DAV/IMoveTarget.php', - 'Sabre\\DAV\\IMultiGet' => $vendorDir . '/sabre/dav/lib/DAV/IMultiGet.php', - 'Sabre\\DAV\\INode' => $vendorDir . '/sabre/dav/lib/DAV/INode.php', - 'Sabre\\DAV\\IProperties' => $vendorDir . '/sabre/dav/lib/DAV/IProperties.php', - 'Sabre\\DAV\\IQuota' => $vendorDir . '/sabre/dav/lib/DAV/IQuota.php', - 'Sabre\\DAV\\Locks\\Backend\\AbstractBackend' => $vendorDir . '/sabre/dav/lib/DAV/Locks/Backend/AbstractBackend.php', - 'Sabre\\DAV\\Locks\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/DAV/Locks/Backend/BackendInterface.php', - 'Sabre\\DAV\\Locks\\Backend\\File' => $vendorDir . '/sabre/dav/lib/DAV/Locks/Backend/File.php', - 'Sabre\\DAV\\Locks\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/DAV/Locks/Backend/PDO.php', - 'Sabre\\DAV\\Locks\\LockInfo' => $vendorDir . '/sabre/dav/lib/DAV/Locks/LockInfo.php', - 'Sabre\\DAV\\Locks\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Locks/Plugin.php', - 'Sabre\\DAV\\MkCol' => $vendorDir . '/sabre/dav/lib/DAV/MkCol.php', - 'Sabre\\DAV\\Mount\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Mount/Plugin.php', - 'Sabre\\DAV\\Node' => $vendorDir . '/sabre/dav/lib/DAV/Node.php', - 'Sabre\\DAV\\PartialUpdate\\IPatchSupport' => $vendorDir . '/sabre/dav/lib/DAV/PartialUpdate/IPatchSupport.php', - 'Sabre\\DAV\\PartialUpdate\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/PartialUpdate/Plugin.php', - 'Sabre\\DAV\\PropFind' => $vendorDir . '/sabre/dav/lib/DAV/PropFind.php', - 'Sabre\\DAV\\PropPatch' => $vendorDir . '/sabre/dav/lib/DAV/PropPatch.php', - 'Sabre\\DAV\\PropertyStorage\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php', - 'Sabre\\DAV\\PropertyStorage\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php', - 'Sabre\\DAV\\PropertyStorage\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/PropertyStorage/Plugin.php', - 'Sabre\\DAV\\Server' => $vendorDir . '/sabre/dav/lib/DAV/Server.php', - 'Sabre\\DAV\\ServerPlugin' => $vendorDir . '/sabre/dav/lib/DAV/ServerPlugin.php', - 'Sabre\\DAV\\Sharing\\ISharedNode' => $vendorDir . '/sabre/dav/lib/DAV/Sharing/ISharedNode.php', - 'Sabre\\DAV\\Sharing\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Sharing/Plugin.php', - 'Sabre\\DAV\\SimpleCollection' => $vendorDir . '/sabre/dav/lib/DAV/SimpleCollection.php', - 'Sabre\\DAV\\SimpleFile' => $vendorDir . '/sabre/dav/lib/DAV/SimpleFile.php', - 'Sabre\\DAV\\StringUtil' => $vendorDir . '/sabre/dav/lib/DAV/StringUtil.php', - 'Sabre\\DAV\\Sync\\ISyncCollection' => $vendorDir . '/sabre/dav/lib/DAV/Sync/ISyncCollection.php', - 'Sabre\\DAV\\Sync\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Sync/Plugin.php', - 'Sabre\\DAV\\TemporaryFileFilterPlugin' => $vendorDir . '/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php', - 'Sabre\\DAV\\Tree' => $vendorDir . '/sabre/dav/lib/DAV/Tree.php', - 'Sabre\\DAV\\UUIDUtil' => $vendorDir . '/sabre/dav/lib/DAV/UUIDUtil.php', - 'Sabre\\DAV\\Version' => $vendorDir . '/sabre/dav/lib/DAV/Version.php', - 'Sabre\\DAV\\Xml\\Element\\Prop' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Element/Prop.php', - 'Sabre\\DAV\\Xml\\Element\\Response' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Element/Response.php', - 'Sabre\\DAV\\Xml\\Element\\Sharee' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Element/Sharee.php', - 'Sabre\\DAV\\Xml\\Property\\Complex' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/Complex.php', - 'Sabre\\DAV\\Xml\\Property\\GetLastModified' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/GetLastModified.php', - 'Sabre\\DAV\\Xml\\Property\\Href' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/Href.php', - 'Sabre\\DAV\\Xml\\Property\\Invite' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/Invite.php', - 'Sabre\\DAV\\Xml\\Property\\LocalHref' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/LocalHref.php', - 'Sabre\\DAV\\Xml\\Property\\LockDiscovery' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/LockDiscovery.php', - 'Sabre\\DAV\\Xml\\Property\\ResourceType' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/ResourceType.php', - 'Sabre\\DAV\\Xml\\Property\\ShareAccess' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/ShareAccess.php', - 'Sabre\\DAV\\Xml\\Property\\SupportedLock' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/SupportedLock.php', - 'Sabre\\DAV\\Xml\\Property\\SupportedMethodSet' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/SupportedMethodSet.php', - 'Sabre\\DAV\\Xml\\Property\\SupportedReportSet' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Property/SupportedReportSet.php', - 'Sabre\\DAV\\Xml\\Request\\Lock' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/Lock.php', - 'Sabre\\DAV\\Xml\\Request\\MkCol' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/MkCol.php', - 'Sabre\\DAV\\Xml\\Request\\PropFind' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/PropFind.php', - 'Sabre\\DAV\\Xml\\Request\\PropPatch' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/PropPatch.php', - 'Sabre\\DAV\\Xml\\Request\\ShareResource' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/ShareResource.php', - 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Request/SyncCollectionReport.php', - 'Sabre\\DAV\\Xml\\Response\\MultiStatus' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Response/MultiStatus.php', - 'Sabre\\DAV\\Xml\\Service' => $vendorDir . '/sabre/dav/lib/DAV/Xml/Service.php', - 'Sabre\\Event\\EventEmitter' => $vendorDir . '/sabre/event/lib/EventEmitter.php', - 'Sabre\\Event\\EventEmitterInterface' => $vendorDir . '/sabre/event/lib/EventEmitterInterface.php', - 'Sabre\\Event\\EventEmitterTrait' => $vendorDir . '/sabre/event/lib/EventEmitterTrait.php', - 'Sabre\\Event\\Loop\\Loop' => $vendorDir . '/sabre/event/lib/Loop/Loop.php', - 'Sabre\\Event\\Promise' => $vendorDir . '/sabre/event/lib/Promise.php', - 'Sabre\\Event\\PromiseAlreadyResolvedException' => $vendorDir . '/sabre/event/lib/PromiseAlreadyResolvedException.php', - 'Sabre\\Event\\Version' => $vendorDir . '/sabre/event/lib/Version.php', - 'Sabre\\HTTP\\Auth\\AWS' => $vendorDir . '/sabre/http/lib/Auth/AWS.php', - 'Sabre\\HTTP\\Auth\\AbstractAuth' => $vendorDir . '/sabre/http/lib/Auth/AbstractAuth.php', - 'Sabre\\HTTP\\Auth\\Basic' => $vendorDir . '/sabre/http/lib/Auth/Basic.php', - 'Sabre\\HTTP\\Auth\\Bearer' => $vendorDir . '/sabre/http/lib/Auth/Bearer.php', - 'Sabre\\HTTP\\Auth\\Digest' => $vendorDir . '/sabre/http/lib/Auth/Digest.php', - 'Sabre\\HTTP\\Client' => $vendorDir . '/sabre/http/lib/Client.php', - 'Sabre\\HTTP\\ClientException' => $vendorDir . '/sabre/http/lib/ClientException.php', - 'Sabre\\HTTP\\ClientHttpException' => $vendorDir . '/sabre/http/lib/ClientHttpException.php', - 'Sabre\\HTTP\\HttpException' => $vendorDir . '/sabre/http/lib/HttpException.php', - 'Sabre\\HTTP\\Message' => $vendorDir . '/sabre/http/lib/Message.php', - 'Sabre\\HTTP\\MessageDecoratorTrait' => $vendorDir . '/sabre/http/lib/MessageDecoratorTrait.php', - 'Sabre\\HTTP\\MessageInterface' => $vendorDir . '/sabre/http/lib/MessageInterface.php', - 'Sabre\\HTTP\\Request' => $vendorDir . '/sabre/http/lib/Request.php', - 'Sabre\\HTTP\\RequestDecorator' => $vendorDir . '/sabre/http/lib/RequestDecorator.php', - 'Sabre\\HTTP\\RequestInterface' => $vendorDir . '/sabre/http/lib/RequestInterface.php', - 'Sabre\\HTTP\\Response' => $vendorDir . '/sabre/http/lib/Response.php', - 'Sabre\\HTTP\\ResponseDecorator' => $vendorDir . '/sabre/http/lib/ResponseDecorator.php', - 'Sabre\\HTTP\\ResponseInterface' => $vendorDir . '/sabre/http/lib/ResponseInterface.php', - 'Sabre\\HTTP\\Sapi' => $vendorDir . '/sabre/http/lib/Sapi.php', - 'Sabre\\HTTP\\URLUtil' => $vendorDir . '/sabre/http/lib/URLUtil.php', - 'Sabre\\HTTP\\Util' => $vendorDir . '/sabre/http/lib/Util.php', - 'Sabre\\HTTP\\Version' => $vendorDir . '/sabre/http/lib/Version.php', - 'Sabre\\Uri\\Version' => $vendorDir . '/sabre/uri/lib/Version.php', - 'Sabre\\VObject\\BirthdayCalendarGenerator' => $vendorDir . '/sabre/vobject/lib/BirthdayCalendarGenerator.php', - 'Sabre\\VObject\\Cli' => $vendorDir . '/sabre/vobject/lib/Cli.php', - 'Sabre\\VObject\\Component' => $vendorDir . '/sabre/vobject/lib/Component.php', - 'Sabre\\VObject\\Component\\Available' => $vendorDir . '/sabre/vobject/lib/Component/Available.php', - 'Sabre\\VObject\\Component\\VAlarm' => $vendorDir . '/sabre/vobject/lib/Component/VAlarm.php', - 'Sabre\\VObject\\Component\\VAvailability' => $vendorDir . '/sabre/vobject/lib/Component/VAvailability.php', - 'Sabre\\VObject\\Component\\VCalendar' => $vendorDir . '/sabre/vobject/lib/Component/VCalendar.php', - 'Sabre\\VObject\\Component\\VCard' => $vendorDir . '/sabre/vobject/lib/Component/VCard.php', - 'Sabre\\VObject\\Component\\VEvent' => $vendorDir . '/sabre/vobject/lib/Component/VEvent.php', - 'Sabre\\VObject\\Component\\VFreeBusy' => $vendorDir . '/sabre/vobject/lib/Component/VFreeBusy.php', - 'Sabre\\VObject\\Component\\VJournal' => $vendorDir . '/sabre/vobject/lib/Component/VJournal.php', - 'Sabre\\VObject\\Component\\VTimeZone' => $vendorDir . '/sabre/vobject/lib/Component/VTimeZone.php', - 'Sabre\\VObject\\Component\\VTodo' => $vendorDir . '/sabre/vobject/lib/Component/VTodo.php', - 'Sabre\\VObject\\DateTimeParser' => $vendorDir . '/sabre/vobject/lib/DateTimeParser.php', - 'Sabre\\VObject\\Document' => $vendorDir . '/sabre/vobject/lib/Document.php', - 'Sabre\\VObject\\ElementList' => $vendorDir . '/sabre/vobject/lib/ElementList.php', - 'Sabre\\VObject\\EofException' => $vendorDir . '/sabre/vobject/lib/EofException.php', - 'Sabre\\VObject\\FreeBusyData' => $vendorDir . '/sabre/vobject/lib/FreeBusyData.php', - 'Sabre\\VObject\\FreeBusyGenerator' => $vendorDir . '/sabre/vobject/lib/FreeBusyGenerator.php', - 'Sabre\\VObject\\ITip\\Broker' => $vendorDir . '/sabre/vobject/lib/ITip/Broker.php', - 'Sabre\\VObject\\ITip\\ITipException' => $vendorDir . '/sabre/vobject/lib/ITip/ITipException.php', - 'Sabre\\VObject\\ITip\\Message' => $vendorDir . '/sabre/vobject/lib/ITip/Message.php', - 'Sabre\\VObject\\ITip\\SameOrganizerForAllComponentsException' => $vendorDir . '/sabre/vobject/lib/ITip/SameOrganizerForAllComponentsException.php', - 'Sabre\\VObject\\InvalidDataException' => $vendorDir . '/sabre/vobject/lib/InvalidDataException.php', - 'Sabre\\VObject\\Node' => $vendorDir . '/sabre/vobject/lib/Node.php', - 'Sabre\\VObject\\PHPUnitAssertions' => $vendorDir . '/sabre/vobject/lib/PHPUnitAssertions.php', - 'Sabre\\VObject\\Parameter' => $vendorDir . '/sabre/vobject/lib/Parameter.php', - 'Sabre\\VObject\\ParseException' => $vendorDir . '/sabre/vobject/lib/ParseException.php', - 'Sabre\\VObject\\Parser\\Json' => $vendorDir . '/sabre/vobject/lib/Parser/Json.php', - 'Sabre\\VObject\\Parser\\MimeDir' => $vendorDir . '/sabre/vobject/lib/Parser/MimeDir.php', - 'Sabre\\VObject\\Parser\\Parser' => $vendorDir . '/sabre/vobject/lib/Parser/Parser.php', - 'Sabre\\VObject\\Parser\\XML' => $vendorDir . '/sabre/vobject/lib/Parser/XML.php', - 'Sabre\\VObject\\Parser\\XML\\Element\\KeyValue' => $vendorDir . '/sabre/vobject/lib/Parser/XML/Element/KeyValue.php', - 'Sabre\\VObject\\Property' => $vendorDir . '/sabre/vobject/lib/Property.php', - 'Sabre\\VObject\\Property\\Binary' => $vendorDir . '/sabre/vobject/lib/Property/Binary.php', - 'Sabre\\VObject\\Property\\Boolean' => $vendorDir . '/sabre/vobject/lib/Property/Boolean.php', - 'Sabre\\VObject\\Property\\FlatText' => $vendorDir . '/sabre/vobject/lib/Property/FlatText.php', - 'Sabre\\VObject\\Property\\FloatValue' => $vendorDir . '/sabre/vobject/lib/Property/FloatValue.php', - 'Sabre\\VObject\\Property\\ICalendar\\CalAddress' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/CalAddress.php', - 'Sabre\\VObject\\Property\\ICalendar\\Date' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/Date.php', - 'Sabre\\VObject\\Property\\ICalendar\\DateTime' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/DateTime.php', - 'Sabre\\VObject\\Property\\ICalendar\\Duration' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/Duration.php', - 'Sabre\\VObject\\Property\\ICalendar\\Period' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/Period.php', - 'Sabre\\VObject\\Property\\ICalendar\\Recur' => $vendorDir . '/sabre/vobject/lib/Property/ICalendar/Recur.php', - 'Sabre\\VObject\\Property\\IntegerValue' => $vendorDir . '/sabre/vobject/lib/Property/IntegerValue.php', - 'Sabre\\VObject\\Property\\Text' => $vendorDir . '/sabre/vobject/lib/Property/Text.php', - 'Sabre\\VObject\\Property\\Time' => $vendorDir . '/sabre/vobject/lib/Property/Time.php', - 'Sabre\\VObject\\Property\\Unknown' => $vendorDir . '/sabre/vobject/lib/Property/Unknown.php', - 'Sabre\\VObject\\Property\\Uri' => $vendorDir . '/sabre/vobject/lib/Property/Uri.php', - 'Sabre\\VObject\\Property\\UtcOffset' => $vendorDir . '/sabre/vobject/lib/Property/UtcOffset.php', - 'Sabre\\VObject\\Property\\VCard\\Date' => $vendorDir . '/sabre/vobject/lib/Property/VCard/Date.php', - 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime' => $vendorDir . '/sabre/vobject/lib/Property/VCard/DateAndOrTime.php', - 'Sabre\\VObject\\Property\\VCard\\DateTime' => $vendorDir . '/sabre/vobject/lib/Property/VCard/DateTime.php', - 'Sabre\\VObject\\Property\\VCard\\LanguageTag' => $vendorDir . '/sabre/vobject/lib/Property/VCard/LanguageTag.php', - 'Sabre\\VObject\\Property\\VCard\\TimeStamp' => $vendorDir . '/sabre/vobject/lib/Property/VCard/TimeStamp.php', - 'Sabre\\VObject\\Reader' => $vendorDir . '/sabre/vobject/lib/Reader.php', - 'Sabre\\VObject\\Recur\\EventIterator' => $vendorDir . '/sabre/vobject/lib/Recur/EventIterator.php', - 'Sabre\\VObject\\Recur\\MaxInstancesExceededException' => $vendorDir . '/sabre/vobject/lib/Recur/MaxInstancesExceededException.php', - 'Sabre\\VObject\\Recur\\NoInstancesException' => $vendorDir . '/sabre/vobject/lib/Recur/NoInstancesException.php', - 'Sabre\\VObject\\Recur\\RDateIterator' => $vendorDir . '/sabre/vobject/lib/Recur/RDateIterator.php', - 'Sabre\\VObject\\Recur\\RRuleIterator' => $vendorDir . '/sabre/vobject/lib/Recur/RRuleIterator.php', - 'Sabre\\VObject\\Settings' => $vendorDir . '/sabre/vobject/lib/Settings.php', - 'Sabre\\VObject\\Splitter\\ICalendar' => $vendorDir . '/sabre/vobject/lib/Splitter/ICalendar.php', - 'Sabre\\VObject\\Splitter\\SplitterInterface' => $vendorDir . '/sabre/vobject/lib/Splitter/SplitterInterface.php', - 'Sabre\\VObject\\Splitter\\VCard' => $vendorDir . '/sabre/vobject/lib/Splitter/VCard.php', - 'Sabre\\VObject\\StringUtil' => $vendorDir . '/sabre/vobject/lib/StringUtil.php', - 'Sabre\\VObject\\TimeZoneUtil' => $vendorDir . '/sabre/vobject/lib/TimeZoneUtil.php', - 'Sabre\\VObject\\UUIDUtil' => $vendorDir . '/sabre/vobject/lib/UUIDUtil.php', - 'Sabre\\VObject\\VCardConverter' => $vendorDir . '/sabre/vobject/lib/VCardConverter.php', - 'Sabre\\VObject\\Version' => $vendorDir . '/sabre/vobject/lib/Version.php', - 'Sabre\\VObject\\Writer' => $vendorDir . '/sabre/vobject/lib/Writer.php', - 'Sabre\\Xml\\ContextStackTrait' => $vendorDir . '/sabre/xml/lib/ContextStackTrait.php', - 'Sabre\\Xml\\Element' => $vendorDir . '/sabre/xml/lib/Element.php', - 'Sabre\\Xml\\Element\\Base' => $vendorDir . '/sabre/xml/lib/Element/Base.php', - 'Sabre\\Xml\\Element\\Cdata' => $vendorDir . '/sabre/xml/lib/Element/Cdata.php', - 'Sabre\\Xml\\Element\\Elements' => $vendorDir . '/sabre/xml/lib/Element/Elements.php', - 'Sabre\\Xml\\Element\\KeyValue' => $vendorDir . '/sabre/xml/lib/Element/KeyValue.php', - 'Sabre\\Xml\\Element\\Uri' => $vendorDir . '/sabre/xml/lib/Element/Uri.php', - 'Sabre\\Xml\\Element\\XmlFragment' => $vendorDir . '/sabre/xml/lib/Element/XmlFragment.php', - 'Sabre\\Xml\\LibXMLException' => $vendorDir . '/sabre/xml/lib/LibXMLException.php', - 'Sabre\\Xml\\ParseException' => $vendorDir . '/sabre/xml/lib/ParseException.php', - 'Sabre\\Xml\\Reader' => $vendorDir . '/sabre/xml/lib/Reader.php', - 'Sabre\\Xml\\Service' => $vendorDir . '/sabre/xml/lib/Service.php', - 'Sabre\\Xml\\Version' => $vendorDir . '/sabre/xml/lib/Version.php', - 'Sabre\\Xml\\Writer' => $vendorDir . '/sabre/xml/lib/Writer.php', - 'Sabre\\Xml\\XmlDeserializable' => $vendorDir . '/sabre/xml/lib/XmlDeserializable.php', - 'Sabre\\Xml\\XmlSerializable' => $vendorDir . '/sabre/xml/lib/XmlSerializable.php', - 'Zotlabs\\Access\\AccessList' => $baseDir . '/Zotlabs/Access/AccessList.php', - 'Zotlabs\\Access\\PermissionLimits' => $baseDir . '/Zotlabs/Access/PermissionLimits.php', - 'Zotlabs\\Access\\PermissionRoles' => $baseDir . '/Zotlabs/Access/PermissionRoles.php', - 'Zotlabs\\Access\\Permissions' => $baseDir . '/Zotlabs/Access/Permissions.php', - 'Zotlabs\\Daemon\\Addon' => $baseDir . '/Zotlabs/Daemon/Addon.php', - 'Zotlabs\\Daemon\\Checksites' => $baseDir . '/Zotlabs/Daemon/Checksites.php', - 'Zotlabs\\Daemon\\Cli_suggest' => $baseDir . '/Zotlabs/Daemon/Cli_suggest.php', - 'Zotlabs\\Daemon\\Cron' => $baseDir . '/Zotlabs/Daemon/Cron.php', - 'Zotlabs\\Daemon\\Cron_daily' => $baseDir . '/Zotlabs/Daemon/Cron_daily.php', - 'Zotlabs\\Daemon\\Cron_weekly' => $baseDir . '/Zotlabs/Daemon/Cron_weekly.php', - 'Zotlabs\\Daemon\\Cronhooks' => $baseDir . '/Zotlabs/Daemon/Cronhooks.php', - 'Zotlabs\\Daemon\\CurlAuth' => $baseDir . '/Zotlabs/Daemon/CurlAuth.php', - 'Zotlabs\\Daemon\\Deliver' => $baseDir . '/Zotlabs/Daemon/Deliver.php', - 'Zotlabs\\Daemon\\Deliver_hooks' => $baseDir . '/Zotlabs/Daemon/Deliver_hooks.php', - 'Zotlabs\\Daemon\\Directory' => $baseDir . '/Zotlabs/Daemon/Directory.php', - 'Zotlabs\\Daemon\\Expire' => $baseDir . '/Zotlabs/Daemon/Expire.php', - 'Zotlabs\\Daemon\\Externals' => $baseDir . '/Zotlabs/Daemon/Externals.php', - 'Zotlabs\\Daemon\\Gprobe' => $baseDir . '/Zotlabs/Daemon/Gprobe.php', - 'Zotlabs\\Daemon\\Importdoc' => $baseDir . '/Zotlabs/Daemon/Importdoc.php', - 'Zotlabs\\Daemon\\Master' => $baseDir . '/Zotlabs/Daemon/Master.php', - 'Zotlabs\\Daemon\\Notifier' => $baseDir . '/Zotlabs/Daemon/Notifier.php', - 'Zotlabs\\Daemon\\Onedirsync' => $baseDir . '/Zotlabs/Daemon/Onedirsync.php', - 'Zotlabs\\Daemon\\Onepoll' => $baseDir . '/Zotlabs/Daemon/Onepoll.php', - 'Zotlabs\\Daemon\\Poller' => $baseDir . '/Zotlabs/Daemon/Poller.php', - 'Zotlabs\\Daemon\\Queue' => $baseDir . '/Zotlabs/Daemon/Queue.php', - 'Zotlabs\\Daemon\\Ratenotif' => $baseDir . '/Zotlabs/Daemon/Ratenotif.php', - 'Zotlabs\\Extend\\Hook' => $baseDir . '/Zotlabs/Extend/Hook.php', - 'Zotlabs\\Identity\\BasicId\\BasicId' => $baseDir . '/Zotlabs/Identity/BasicId.php', - 'Zotlabs\\Identity\\ProfilePhoto\\ProfilePhoto' => $baseDir . '/Zotlabs/Identity/ProfilePhoto.php', - 'Zotlabs\\Lib\\AConfig' => $baseDir . '/Zotlabs/Lib/AConfig.php', - 'Zotlabs\\Lib\\AbConfig' => $baseDir . '/Zotlabs/Lib/AbConfig.php', - 'Zotlabs\\Lib\\Api_router' => $baseDir . '/Zotlabs/Lib/Api_router.php', - 'Zotlabs\\Lib\\Apps' => $baseDir . '/Zotlabs/Lib/Apps.php', - 'Zotlabs\\Lib\\Cache' => $baseDir . '/Zotlabs/Lib/Cache.php', - 'Zotlabs\\Lib\\Chatroom' => $baseDir . '/Zotlabs/Lib/Chatroom.php', - 'Zotlabs\\Lib\\Config' => $baseDir . '/Zotlabs/Lib/Config.php', - 'Zotlabs\\Lib\\Enotify' => $baseDir . '/Zotlabs/Lib/Enotify.php', - 'Zotlabs\\Lib\\ExtendedZip' => $baseDir . '/Zotlabs/Lib/ExtendedZip.php', - 'Zotlabs\\Lib\\IConfig' => $baseDir . '/Zotlabs/Lib/IConfig.php', - 'Zotlabs\\Lib\\NativeWiki' => $baseDir . '/Zotlabs/Lib/NativeWiki.php', - 'Zotlabs\\Lib\\NativeWikiPage' => $baseDir . '/Zotlabs/Lib/NativeWikiPage.php', - 'Zotlabs\\Lib\\PConfig' => $baseDir . '/Zotlabs/Lib/PConfig.php', - 'Zotlabs\\Lib\\Permcat' => $baseDir . '/Zotlabs/Lib/Permcat.php', - 'Zotlabs\\Lib\\PermissionDescription' => $baseDir . '/Zotlabs/Lib/PermissionDescription.php', - 'Zotlabs\\Lib\\ProtoDriver' => $baseDir . '/Zotlabs/Lib/ProtoDriver.php', - 'Zotlabs\\Lib\\SuperCurl' => $baseDir . '/Zotlabs/Lib/SuperCurl.php', - 'Zotlabs\\Lib\\System' => $baseDir . '/Zotlabs/Lib/System.php', - 'Zotlabs\\Lib\\Techlevels' => $baseDir . '/Zotlabs/Lib/Techlevels.php', - 'Zotlabs\\Lib\\ThreadItem' => $baseDir . '/Zotlabs/Lib/ThreadItem.php', - 'Zotlabs\\Lib\\ThreadStream' => $baseDir . '/Zotlabs/Lib/ThreadStream.php', - 'Zotlabs\\Lib\\XConfig' => $baseDir . '/Zotlabs/Lib/XConfig.php', - 'Zotlabs\\Lib\\ZotDriver' => $baseDir . '/Zotlabs/Lib/ZotDriver.php', - 'Zotlabs\\Module\\Achievements' => $baseDir . '/Zotlabs/Module/Achievements.php', - 'Zotlabs\\Module\\Acl' => $baseDir . '/Zotlabs/Module/Acl.php', - 'Zotlabs\\Module\\Admin' => $baseDir . '/Zotlabs/Module/Admin.php', - 'Zotlabs\\Module\\Admin\\Account_edit' => $baseDir . '/Zotlabs/Module/Admin/Account_edit.php', - 'Zotlabs\\Module\\Admin\\Accounts' => $baseDir . '/Zotlabs/Module/Admin/Accounts.php', - 'Zotlabs\\Module\\Admin\\Channels' => $baseDir . '/Zotlabs/Module/Admin/Channels.php', - 'Zotlabs\\Module\\Admin\\Dbsync' => $baseDir . '/Zotlabs/Module/Admin/Dbsync.php', - 'Zotlabs\\Module\\Admin\\Features' => $baseDir . '/Zotlabs/Module/Admin/Features.php', - 'Zotlabs\\Module\\Admin\\Logs' => $baseDir . '/Zotlabs/Module/Admin/Logs.php', - 'Zotlabs\\Module\\Admin\\Plugins' => $baseDir . '/Zotlabs/Module/Admin/Plugins.php', - 'Zotlabs\\Module\\Admin\\Profs' => $baseDir . '/Zotlabs/Module/Admin/Profs.php', - 'Zotlabs\\Module\\Admin\\Queue' => $baseDir . '/Zotlabs/Module/Admin/Queue.php', - 'Zotlabs\\Module\\Admin\\Security' => $baseDir . '/Zotlabs/Module/Admin/Security.php', - 'Zotlabs\\Module\\Admin\\Site' => $baseDir . '/Zotlabs/Module/Admin/Site.php', - 'Zotlabs\\Module\\Admin\\Themes' => $baseDir . '/Zotlabs/Module/Admin/Themes.php', - 'Zotlabs\\Module\\Api' => $baseDir . '/Zotlabs/Module/Api.php', - 'Zotlabs\\Module\\Appman' => $baseDir . '/Zotlabs/Module/Appman.php', - 'Zotlabs\\Module\\Apps' => $baseDir . '/Zotlabs/Module/Apps.php', - 'Zotlabs\\Module\\Attach' => $baseDir . '/Zotlabs/Module/Attach.php', - 'Zotlabs\\Module\\Authtest' => $baseDir . '/Zotlabs/Module/Authtest.php', - 'Zotlabs\\Module\\Block' => $baseDir . '/Zotlabs/Module/Block.php', - 'Zotlabs\\Module\\Blocks' => $baseDir . '/Zotlabs/Module/Blocks.php', - 'Zotlabs\\Module\\Bookmarks' => $baseDir . '/Zotlabs/Module/Bookmarks.php', - 'Zotlabs\\Module\\Branchtopic' => $baseDir . '/Zotlabs/Module/Branchtopic.php', - 'Zotlabs\\Module\\Cal' => $baseDir . '/Zotlabs/Module/Cal.php', - 'Zotlabs\\Module\\Channel' => $baseDir . '/Zotlabs/Module/Channel.php', - 'Zotlabs\\Module\\Chanview' => $baseDir . '/Zotlabs/Module/Chanview.php', - 'Zotlabs\\Module\\Chat' => $baseDir . '/Zotlabs/Module/Chat.php', - 'Zotlabs\\Module\\Chatsvc' => $baseDir . '/Zotlabs/Module/Chatsvc.php', - 'Zotlabs\\Module\\Cloud' => $baseDir . '/Zotlabs/Module/Cloud.php', - 'Zotlabs\\Module\\Common' => $baseDir . '/Zotlabs/Module/Common.php', - 'Zotlabs\\Module\\Connect' => $baseDir . '/Zotlabs/Module/Connect.php', - 'Zotlabs\\Module\\Connections' => $baseDir . '/Zotlabs/Module/Connections.php', - 'Zotlabs\\Module\\Connedit' => $baseDir . '/Zotlabs/Module/Connedit.php', - 'Zotlabs\\Module\\Contactgroup' => $baseDir . '/Zotlabs/Module/Contactgroup.php', - 'Zotlabs\\Module\\Cover_photo' => $baseDir . '/Zotlabs/Module/Cover_photo.php', - 'Zotlabs\\Module\\Dav' => $baseDir . '/Zotlabs/Module/Dav.php', - 'Zotlabs\\Module\\Directory' => $baseDir . '/Zotlabs/Module/Directory.php', - 'Zotlabs\\Module\\Dirsearch' => $baseDir . '/Zotlabs/Module/Dirsearch.php', - 'Zotlabs\\Module\\Display' => $baseDir . '/Zotlabs/Module/Display.php', - 'Zotlabs\\Module\\Dreport' => $baseDir . '/Zotlabs/Module/Dreport.php', - 'Zotlabs\\Module\\Editblock' => $baseDir . '/Zotlabs/Module/Editblock.php', - 'Zotlabs\\Module\\Editlayout' => $baseDir . '/Zotlabs/Module/Editlayout.php', - 'Zotlabs\\Module\\Editpost' => $baseDir . '/Zotlabs/Module/Editpost.php', - 'Zotlabs\\Module\\Editwebpage' => $baseDir . '/Zotlabs/Module/Editwebpage.php', - 'Zotlabs\\Module\\Embedphotos' => $baseDir . '/Zotlabs/Module/Embedphotos.php', - 'Zotlabs\\Module\\Events' => $baseDir . '/Zotlabs/Module/Events.php', - 'Zotlabs\\Module\\Fbrowser' => $baseDir . '/Zotlabs/Module/Fbrowser.php', - 'Zotlabs\\Module\\Feed' => $baseDir . '/Zotlabs/Module/Feed.php', - 'Zotlabs\\Module\\Fhublocs' => $baseDir . '/Zotlabs/Module/Fhublocs.php', - 'Zotlabs\\Module\\File_upload' => $baseDir . '/Zotlabs/Module/File_upload.php', - 'Zotlabs\\Module\\Filer' => $baseDir . '/Zotlabs/Module/Filer.php', - 'Zotlabs\\Module\\Filerm' => $baseDir . '/Zotlabs/Module/Filerm.php', - 'Zotlabs\\Module\\Filestorage' => $baseDir . '/Zotlabs/Module/Filestorage.php', - 'Zotlabs\\Module\\Follow' => $baseDir . '/Zotlabs/Module/Follow.php', - 'Zotlabs\\Module\\Getfile' => $baseDir . '/Zotlabs/Module/Getfile.php', - 'Zotlabs\\Module\\Group' => $baseDir . '/Zotlabs/Module/Group.php', - 'Zotlabs\\Module\\Hcard' => $baseDir . '/Zotlabs/Module/Hcard.php', - 'Zotlabs\\Module\\Help' => $baseDir . '/Zotlabs/Module/Help.php', - 'Zotlabs\\Module\\Home' => $baseDir . '/Zotlabs/Module/Home.php', - 'Zotlabs\\Module\\Hostxrd' => $baseDir . '/Zotlabs/Module/Hostxrd.php', - 'Zotlabs\\Module\\Impel' => $baseDir . '/Zotlabs/Module/Impel.php', - 'Zotlabs\\Module\\Import' => $baseDir . '/Zotlabs/Module/Import.php', - 'Zotlabs\\Module\\Import_items' => $baseDir . '/Zotlabs/Module/Import_items.php', - 'Zotlabs\\Module\\Invite' => $baseDir . '/Zotlabs/Module/Invite.php', - 'Zotlabs\\Module\\Item' => $baseDir . '/Zotlabs/Module/Item.php', - 'Zotlabs\\Module\\Lang' => $baseDir . '/Zotlabs/Module/Lang.php', - 'Zotlabs\\Module\\Layouts' => $baseDir . '/Zotlabs/Module/Layouts.php', - 'Zotlabs\\Module\\Like' => $baseDir . '/Zotlabs/Module/Like.php', - 'Zotlabs\\Module\\Linkinfo' => $baseDir . '/Zotlabs/Module/Linkinfo.php', - 'Zotlabs\\Module\\Lockview' => $baseDir . '/Zotlabs/Module/Lockview.php', - 'Zotlabs\\Module\\Locs' => $baseDir . '/Zotlabs/Module/Locs.php', - 'Zotlabs\\Module\\Login' => $baseDir . '/Zotlabs/Module/Login.php', - 'Zotlabs\\Module\\Lostpass' => $baseDir . '/Zotlabs/Module/Lostpass.php', - 'Zotlabs\\Module\\Magic' => $baseDir . '/Zotlabs/Module/Magic.php', - 'Zotlabs\\Module\\Mail' => $baseDir . '/Zotlabs/Module/Mail.php', - 'Zotlabs\\Module\\Manage' => $baseDir . '/Zotlabs/Module/Manage.php', - 'Zotlabs\\Module\\Menu' => $baseDir . '/Zotlabs/Module/Menu.php', - 'Zotlabs\\Module\\Message' => $baseDir . '/Zotlabs/Module/Message.php', - 'Zotlabs\\Module\\Mitem' => $baseDir . '/Zotlabs/Module/Mitem.php', - 'Zotlabs\\Module\\Mood' => $baseDir . '/Zotlabs/Module/Mood.php', - 'Zotlabs\\Module\\Network' => $baseDir . '/Zotlabs/Module/Network.php', - 'Zotlabs\\Module\\New_channel' => $baseDir . '/Zotlabs/Module/New_channel.php', - 'Zotlabs\\Module\\Nojs' => $baseDir . '/Zotlabs/Module/Nojs.php', - 'Zotlabs\\Module\\Notes' => $baseDir . '/Zotlabs/Module/Notes.php', - 'Zotlabs\\Module\\Notifications' => $baseDir . '/Zotlabs/Module/Notifications.php', - 'Zotlabs\\Module\\Notify' => $baseDir . '/Zotlabs/Module/Notify.php', - 'Zotlabs\\Module\\Oembed' => $baseDir . '/Zotlabs/Module/Oembed.php', - 'Zotlabs\\Module\\Oep' => $baseDir . '/Zotlabs/Module/Oep.php', - 'Zotlabs\\Module\\Oexchange' => $baseDir . '/Zotlabs/Module/Oexchange.php', - 'Zotlabs\\Module\\Online' => $baseDir . '/Zotlabs/Module/Online.php', - 'Zotlabs\\Module\\Page' => $baseDir . '/Zotlabs/Module/Page.php', - 'Zotlabs\\Module\\Pconfig' => $baseDir . '/Zotlabs/Module/Pconfig.php', - 'Zotlabs\\Module\\Pdledit' => $baseDir . '/Zotlabs/Module/Pdledit.php', - 'Zotlabs\\Module\\Permcat' => $baseDir . '/Zotlabs/Module/Permcat.php', - 'Zotlabs\\Module\\Photo' => $baseDir . '/Zotlabs/Module/Photo.php', - 'Zotlabs\\Module\\Photos' => $baseDir . '/Zotlabs/Module/Photos.php', - 'Zotlabs\\Module\\Ping' => $baseDir . '/Zotlabs/Module/Ping.php', - 'Zotlabs\\Module\\Poco' => $baseDir . '/Zotlabs/Module/Poco.php', - 'Zotlabs\\Module\\Poke' => $baseDir . '/Zotlabs/Module/Poke.php', - 'Zotlabs\\Module\\Post' => $baseDir . '/Zotlabs/Module/Post.php', - 'Zotlabs\\Module\\Prate' => $baseDir . '/Zotlabs/Module/Prate.php', - 'Zotlabs\\Module\\Pretheme' => $baseDir . '/Zotlabs/Module/Pretheme.php', - 'Zotlabs\\Module\\Probe' => $baseDir . '/Zotlabs/Module/Probe.php', - 'Zotlabs\\Module\\Profile' => $baseDir . '/Zotlabs/Module/Profile.php', - 'Zotlabs\\Module\\Profile_photo' => $baseDir . '/Zotlabs/Module/Profile_photo.php', - 'Zotlabs\\Module\\Profiles' => $baseDir . '/Zotlabs/Module/Profiles.php', - 'Zotlabs\\Module\\Profperm' => $baseDir . '/Zotlabs/Module/Profperm.php', - 'Zotlabs\\Module\\Pubsites' => $baseDir . '/Zotlabs/Module/Pubsites.php', - 'Zotlabs\\Module\\Pubstream' => $baseDir . '/Zotlabs/Module/Pubstream.php', - 'Zotlabs\\Module\\Randprof' => $baseDir . '/Zotlabs/Module/Randprof.php', - 'Zotlabs\\Module\\Rate' => $baseDir . '/Zotlabs/Module/Rate.php', - 'Zotlabs\\Module\\Ratings' => $baseDir . '/Zotlabs/Module/Ratings.php', - 'Zotlabs\\Module\\Ratingsearch' => $baseDir . '/Zotlabs/Module/Ratingsearch.php', - 'Zotlabs\\Module\\Rbmark' => $baseDir . '/Zotlabs/Module/Rbmark.php', - 'Zotlabs\\Module\\React' => $baseDir . '/Zotlabs/Module/React.php', - 'Zotlabs\\Module\\Regdir' => $baseDir . '/Zotlabs/Module/Regdir.php', - 'Zotlabs\\Module\\Register' => $baseDir . '/Zotlabs/Module/Register.php', - 'Zotlabs\\Module\\Regmod' => $baseDir . '/Zotlabs/Module/Regmod.php', - 'Zotlabs\\Module\\Regver' => $baseDir . '/Zotlabs/Module/Regver.php', - 'Zotlabs\\Module\\Removeaccount' => $baseDir . '/Zotlabs/Module/Removeaccount.php', - 'Zotlabs\\Module\\Removeme' => $baseDir . '/Zotlabs/Module/Removeme.php', - 'Zotlabs\\Module\\Rmagic' => $baseDir . '/Zotlabs/Module/Rmagic.php', - 'Zotlabs\\Module\\Rpost' => $baseDir . '/Zotlabs/Module/Rpost.php', - 'Zotlabs\\Module\\Search' => $baseDir . '/Zotlabs/Module/Search.php', - 'Zotlabs\\Module\\Search_ac' => $baseDir . '/Zotlabs/Module/Search_ac.php', - 'Zotlabs\\Module\\Service_limits' => $baseDir . '/Zotlabs/Module/Service_limits.php', - 'Zotlabs\\Module\\Settings' => $baseDir . '/Zotlabs/Module/Settings.php', - 'Zotlabs\\Module\\Settings\\Account' => $baseDir . '/Zotlabs/Module/Settings/Account.php', - 'Zotlabs\\Module\\Settings\\Channel' => $baseDir . '/Zotlabs/Module/Settings/Channel.php', - 'Zotlabs\\Module\\Settings\\Display' => $baseDir . '/Zotlabs/Module/Settings/Display.php', - 'Zotlabs\\Module\\Settings\\Featured' => $baseDir . '/Zotlabs/Module/Settings/Featured.php', - 'Zotlabs\\Module\\Settings\\Features' => $baseDir . '/Zotlabs/Module/Settings/Features.php', - 'Zotlabs\\Module\\Settings\\Oauth' => $baseDir . '/Zotlabs/Module/Settings/Oauth.php', - 'Zotlabs\\Module\\Settings\\Permcats' => $baseDir . '/Zotlabs/Module/Settings/Permcats.php', - 'Zotlabs\\Module\\Settings\\Tokens' => $baseDir . '/Zotlabs/Module/Settings/Tokens.php', - 'Zotlabs\\Module\\Setup' => $baseDir . '/Zotlabs/Module/Setup.php', - 'Zotlabs\\Module\\Share' => $baseDir . '/Zotlabs/Module/Share.php', - 'Zotlabs\\Module\\Sharedwithme' => $baseDir . '/Zotlabs/Module/Sharedwithme.php', - 'Zotlabs\\Module\\Siteinfo' => $baseDir . '/Zotlabs/Module/Siteinfo.php', - 'Zotlabs\\Module\\Siteinfo_json' => $baseDir . '/Zotlabs/Module/Siteinfo_json.php', - 'Zotlabs\\Module\\Sitelist' => $baseDir . '/Zotlabs/Module/Sitelist.php', - 'Zotlabs\\Module\\Smilies' => $baseDir . '/Zotlabs/Module/Smilies.php', - 'Zotlabs\\Module\\Snap' => $baseDir . '/Zotlabs/Module/Snap.php', - 'Zotlabs\\Module\\Sources' => $baseDir . '/Zotlabs/Module/Sources.php', - 'Zotlabs\\Module\\Sslify' => $baseDir . '/Zotlabs/Module/Sslify.php', - 'Zotlabs\\Module\\Starred' => $baseDir . '/Zotlabs/Module/Starred.php', - 'Zotlabs\\Module\\Subthread' => $baseDir . '/Zotlabs/Module/Subthread.php', - 'Zotlabs\\Module\\Suggest' => $baseDir . '/Zotlabs/Module/Suggest.php', - 'Zotlabs\\Module\\Tagger' => $baseDir . '/Zotlabs/Module/Tagger.php', - 'Zotlabs\\Module\\Tagrm' => $baseDir . '/Zotlabs/Module/Tagrm.php', - 'Zotlabs\\Module\\Tasks' => $baseDir . '/Zotlabs/Module/Tasks.php', - 'Zotlabs\\Module\\Theme_info' => $baseDir . '/Zotlabs/Module/Theme_info.php', - 'Zotlabs\\Module\\Thing' => $baseDir . '/Zotlabs/Module/Thing.php', - 'Zotlabs\\Module\\Toggle_mobile' => $baseDir . '/Zotlabs/Module/Toggle_mobile.php', - 'Zotlabs\\Module\\Toggle_safesearch' => $baseDir . '/Zotlabs/Module/Toggle_safesearch.php', - 'Zotlabs\\Module\\Uexport' => $baseDir . '/Zotlabs/Module/Uexport.php', - 'Zotlabs\\Module\\Update_channel' => $baseDir . '/Zotlabs/Module/Update_channel.php', - 'Zotlabs\\Module\\Update_display' => $baseDir . '/Zotlabs/Module/Update_display.php', - 'Zotlabs\\Module\\Update_home' => $baseDir . '/Zotlabs/Module/Update_home.php', - 'Zotlabs\\Module\\Update_network' => $baseDir . '/Zotlabs/Module/Update_network.php', - 'Zotlabs\\Module\\Update_pubstream' => $baseDir . '/Zotlabs/Module/Update_pubstream.php', - 'Zotlabs\\Module\\Update_search' => $baseDir . '/Zotlabs/Module/Update_search.php', - 'Zotlabs\\Module\\View' => $baseDir . '/Zotlabs/Module/View.php', - 'Zotlabs\\Module\\Viewconnections' => $baseDir . '/Zotlabs/Module/Viewconnections.php', - 'Zotlabs\\Module\\Viewsrc' => $baseDir . '/Zotlabs/Module/Viewsrc.php', - 'Zotlabs\\Module\\Wall_attach' => $baseDir . '/Zotlabs/Module/Wall_attach.php', - 'Zotlabs\\Module\\Wall_upload' => $baseDir . '/Zotlabs/Module/Wall_upload.php', - 'Zotlabs\\Module\\Webfinger' => $baseDir . '/Zotlabs/Module/Webfinger.php', - 'Zotlabs\\Module\\Webpages' => $baseDir . '/Zotlabs/Module/Webpages.php', - 'Zotlabs\\Module\\Well_known' => $baseDir . '/Zotlabs/Module/Well_known.php', - 'Zotlabs\\Module\\Wfinger' => $baseDir . '/Zotlabs/Module/Wfinger.php', - 'Zotlabs\\Module\\Wiki' => $baseDir . '/Zotlabs/Module/Wiki.php', - 'Zotlabs\\Module\\Xchan' => $baseDir . '/Zotlabs/Module/Xchan.php', - 'Zotlabs\\Module\\Xpoco' => $baseDir . '/Zotlabs/Module/Xpoco.php', - 'Zotlabs\\Module\\Xrd' => $baseDir . '/Zotlabs/Module/Xrd.php', - 'Zotlabs\\Module\\Xref' => $baseDir . '/Zotlabs/Module/Xref.php', - 'Zotlabs\\Module\\Zfinger' => $baseDir . '/Zotlabs/Module/Zfinger.php', - 'Zotlabs\\Module\\Zotfeed' => $baseDir . '/Zotlabs/Module/Zotfeed.php', - 'Zotlabs\\Module\\Zping' => $baseDir . '/Zotlabs/Module/Zping.php', - 'Zotlabs\\Render\\Comanche' => $baseDir . '/Zotlabs/Render/Comanche.php', - 'Zotlabs\\Render\\SimpleTemplate' => $baseDir . '/Zotlabs/Render/SimpleTemplate.php', - 'Zotlabs\\Render\\SmartyInterface' => $baseDir . '/Zotlabs/Render/SmartyInterface.php', - 'Zotlabs\\Render\\SmartyTemplate' => $baseDir . '/Zotlabs/Render/SmartyTemplate.php', - 'Zotlabs\\Render\\TemplateEngine' => $baseDir . '/Zotlabs/Render/TemplateEngine.php', - 'Zotlabs\\Render\\Theme' => $baseDir . '/Zotlabs/Render/Theme.php', - 'Zotlabs\\Storage\\BasicAuth' => $baseDir . '/Zotlabs/Storage/BasicAuth.php', - 'Zotlabs\\Storage\\Browser' => $baseDir . '/Zotlabs/Storage/Browser.php', - 'Zotlabs\\Storage\\CalDAVClient' => $baseDir . '/Zotlabs/Storage/CalDAVClient.php', - 'Zotlabs\\Storage\\Directory' => $baseDir . '/Zotlabs/Storage/Directory.php', - 'Zotlabs\\Storage\\File' => $baseDir . '/Zotlabs/Storage/File.php', - 'Zotlabs\\Storage\\GitRepo' => $baseDir . '/Zotlabs/Storage/GitRepo.php', - 'Zotlabs\\Text\\Tagadelic' => $baseDir . '/Zotlabs/Text/Tagadelic.php', - 'Zotlabs\\Web\\CheckJS' => $baseDir . '/Zotlabs/Web/CheckJS.php', - 'Zotlabs\\Web\\Controller' => $baseDir . '/Zotlabs/Web/Controller.php', - 'Zotlabs\\Web\\HTTPHeaders' => $baseDir . '/Zotlabs/Web/HTTPHeaders.php', - 'Zotlabs\\Web\\HttpMeta' => $baseDir . '/Zotlabs/Web/HttpMeta.php', - 'Zotlabs\\Web\\Router' => $baseDir . '/Zotlabs/Web/Router.php', - 'Zotlabs\\Web\\Session' => $baseDir . '/Zotlabs/Web/Session.php', - 'Zotlabs\\Web\\SessionHandler' => $baseDir . '/Zotlabs/Web/SessionHandler.php', - 'Zotlabs\\Web\\SubModule' => $baseDir . '/Zotlabs/Web/SubModule.php', - 'Zotlabs\\Web\\WebServer' => $baseDir . '/Zotlabs/Web/WebServer.php', - 'Zotlabs\\Zot\\Auth' => $baseDir . '/Zotlabs/Zot/Auth.php', - 'Zotlabs\\Zot\\DReport' => $baseDir . '/Zotlabs/Zot/DReport.php', - 'Zotlabs\\Zot\\Finger' => $baseDir . '/Zotlabs/Zot/Finger.php', - 'Zotlabs\\Zot\\IHandler' => $baseDir . '/Zotlabs/Zot/IHandler.php', - 'Zotlabs\\Zot\\Receiver' => $baseDir . '/Zotlabs/Zot/Receiver.php', - 'Zotlabs\\Zot\\Verify' => $baseDir . '/Zotlabs/Zot/Verify.php', - 'Zotlabs\\Zot\\ZotHandler' => $baseDir . '/Zotlabs/Zot/ZotHandler.php', ); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index 01914946c..d880bb6f5 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'OAuth2' => array($vendorDir . '/bshaffer/oauth2-server-php/src'), 'Michelf' => array($vendorDir . '/michelf/php-markdown'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index bcae78e29..6200547d3 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -23,35 +23,24 @@ class ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d', 'loadClassLoader')); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); } $loader->register(true); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } + $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $fileIdentifier => $file) { composerRequire7b34d7e50a62201ec5d5e526a5b8b35d($fileIdentifier, $file); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 0fb88e5a1..1a0de2cb8 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,157 +1,5 @@ [ { - "name": "sabre/uri", - "version": "1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/fruux/sabre-uri.git", - "reference": "9012116434d84ef6e5e37a89dfdbfbe2204a8704" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fruux/sabre-uri/zipball/9012116434d84ef6e5e37a89dfdbfbe2204a8704", - "reference": "9012116434d84ef6e5e37a89dfdbfbe2204a8704", - "shasum": "" - }, - "require": { - "php": ">=5.4.7" - }, - "require-dev": { - "phpunit/phpunit": "*", - "sabre/cs": "~0.0.1" - }, - "time": "2016-03-08T02:29:27+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Sabre\\Uri\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "Functions for making sense out of URIs.", - "homepage": "http://sabre.io/uri/", - "keywords": [ - "rfc3986", - "uri", - "url" - ] - }, - { - "name": "sabre/vobject", - "version": "4.1.1", - "version_normalized": "4.1.1.0", - "source": { - "type": "git", - "url": "https://github.com/fruux/sabre-vobject.git", - "reference": "a3a59b06947f122af2d45d52b72172cdc1efd68f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/a3a59b06947f122af2d45d52b72172cdc1efd68f", - "reference": "a3a59b06947f122af2d45d52b72172cdc1efd68f", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.5", - "sabre/xml": "~1.1" - }, - "require-dev": { - "phpunit/phpunit": "*", - "sabre/cs": "~0.0.3" - }, - "suggest": { - "hoa/bench": "If you would like to run the benchmark scripts" - }, - "time": "2016-07-15T19:52:17+00:00", - "bin": [ - "bin/vobject", - "bin/generate_vcards" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\VObject\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - }, - { - "name": "Dominik Tobschall", - "email": "dominik@fruux.com", - "homepage": "http://tobschall.de/", - "role": "Developer" - }, - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net", - "homepage": "http://mnt.io/", - "role": "Developer" - } - ], - "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", - "homepage": "http://sabre.io/vobject/", - "keywords": [ - "availability", - "freebusy", - "iCalendar", - "ical", - "ics", - "jCal", - "jCard", - "recurrence", - "rfc2425", - "rfc2426", - "rfc2739", - "rfc4770", - "rfc5545", - "rfc5546", - "rfc6321", - "rfc6350", - "rfc6351", - "rfc6474", - "rfc6638", - "rfc6715", - "rfc6868", - "vCalendar", - "vCard", - "vcf", - "xCal", - "xCard" - ] - }, - { "name": "sabre/event", "version": "3.0.0", "version_normalized": "3.0.0.0", @@ -173,7 +21,7 @@ "phpunit/phpunit": "*", "sabre/cs": "~0.0.4" }, - "time": "2015-11-05T20:14:39+00:00", + "time": "2015-11-05 20:14:39", "type": "library", "installation-source": "dist", "autoload": { @@ -211,148 +59,6 @@ ] }, { - "name": "sabre/http", - "version": "4.2.1", - "version_normalized": "4.2.1.0", - "source": { - "type": "git", - "url": "https://github.com/fruux/sabre-http.git", - "reference": "2e93bc8321524c67be4ca5b8415daebd4c8bf85e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fruux/sabre-http/zipball/2e93bc8321524c67be4ca5b8415daebd4c8bf85e", - "reference": "2e93bc8321524c67be4ca5b8415daebd4c8bf85e", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.4", - "sabre/event": ">=1.0.0,<4.0.0", - "sabre/uri": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.3", - "sabre/cs": "~0.0.1" - }, - "suggest": { - "ext-curl": " to make http requests with the Client class" - }, - "time": "2016-01-06T23:00:08+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Sabre\\HTTP\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "The sabre/http library provides utilities for dealing with http requests and responses. ", - "homepage": "https://github.com/fruux/sabre-http", - "keywords": [ - "http" - ] - }, - { - "name": "sabre/dav", - "version": "3.2.0", - "version_normalized": "3.2.0.0", - "source": { - "type": "git", - "url": "https://github.com/fruux/sabre-dav.git", - "reference": "5b9737cc2f0182e368d14c80df7f6b2d77dc1457" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fruux/sabre-dav/zipball/5b9737cc2f0182e368d14c80df7f6b2d77dc1457", - "reference": "5b9737cc2f0182e368d14c80df7f6b2d77dc1457", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-date": "*", - "ext-dom": "*", - "ext-iconv": "*", - "ext-mbstring": "*", - "ext-pcre": "*", - "ext-simplexml": "*", - "ext-spl": "*", - "lib-libxml": ">=2.7.0", - "php": ">=5.5.0", - "psr/log": "^1.0", - "sabre/event": ">=2.0.0, <4.0.0", - "sabre/http": "^4.2.1", - "sabre/uri": "^1.0.1", - "sabre/vobject": "^4.1.0", - "sabre/xml": "^1.4.0" - }, - "require-dev": { - "evert/phpdoc-md": "~0.1.0", - "monolog/monolog": "^1.18", - "phpunit/phpunit": "> 4.8, <=6.0.0", - "sabre/cs": "~0.0.5" - }, - "suggest": { - "ext-curl": "*", - "ext-pdo": "*" - }, - "time": "2016-06-28T02:44:05+00:00", - "bin": [ - "bin/sabredav", - "bin/naturalselection" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\DAV\\": "lib/DAV/", - "Sabre\\DAVACL\\": "lib/DAVACL/", - "Sabre\\CalDAV\\": "lib/CalDAV/", - "Sabre\\CardDAV\\": "lib/CardDAV/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "WebDAV Framework for PHP", - "homepage": "http://sabre.io/", - "keywords": [ - "CalDAV", - "CardDAV", - "WebDAV", - "framework", - "iCalendar" - ] - }, - { "name": "sabre/xml", "version": "1.5.0", "version_normalized": "1.5.0.0", @@ -379,7 +85,7 @@ "phpunit/phpunit": "*", "sabre/cs": "~1.0.0" }, - "time": "2016-10-09T22:57:52+00:00", + "time": "2016-10-09 22:57:52", "type": "library", "installation-source": "dist", "autoload": { @@ -435,7 +141,7 @@ "require": { "php": ">=5.3.0" }, - "time": "2016-10-10T12:19:37+00:00", + "time": "2016-10-10 12:19:37", "type": "library", "extra": { "branch-alias": { @@ -484,7 +190,7 @@ "require": { "php": ">=5.3.0" }, - "time": "2016-10-29T18:58:20+00:00", + "time": "2016-10-29 18:58:20", "type": "library", "extra": { "branch-alias": { @@ -540,7 +246,7 @@ "require-dev": { "phpunit/phpunit": "^4.8" }, - "time": "2016-09-21T13:01:43+00:00", + "time": "2016-09-21 13:01:43", "type": "lib", "installation-source": "dist", "autoload": { @@ -576,5 +282,358 @@ "markdown", "markdownify" ] + }, + { + "name": "bshaffer/oauth2-server-php", + "version": "v1.9.0", + "version_normalized": "1.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/bshaffer/oauth2-server-php.git", + "reference": "8856aed1a98d6da596ae3f9b8095b5c7a1581697" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/8856aed1a98d6da596ae3f9b8095b5c7a1581697", + "reference": "8856aed1a98d6da596ae3f9b8095b5c7a1581697", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.8", + "firebase/php-jwt": "~2.2", + "mongodb/mongodb": "^1.1", + "predis/predis": "dev-master", + "thobbs/phpcassa": "dev-master" + }, + "suggest": { + "aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage", + "firebase/php-jwt": "~1.1 is required to use MondoDB storage", + "predis/predis": "Required to use Redis storage", + "thobbs/phpcassa": "Required to use Cassandra storage" + }, + "time": "2017-01-06 23:20:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "OAuth2": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brent Shaffer", + "email": "bshafs@gmail.com", + "homepage": "http://brentertainment.com" + } + ], + "description": "OAuth2 Server for PHP", + "homepage": "http://github.com/bshaffer/oauth2-server-php", + "keywords": [ + "auth", + "oauth", + "oauth2" + ] + }, + { + "name": "sabre/uri", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-uri.git", + "reference": "ada354d83579565949d80b2e15593c2371225e61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-uri/zipball/ada354d83579565949d80b2e15593c2371225e61", + "reference": "ada354d83579565949d80b2e15593c2371225e61", + "shasum": "" + }, + "require": { + "php": ">=5.4.7" + }, + "require-dev": { + "phpunit/phpunit": ">=4.0,<6.0", + "sabre/cs": "~1.0.0" + }, + "time": "2017-02-20 19:59:28", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\Uri\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "Functions for making sense out of URIs.", + "homepage": "http://sabre.io/uri/", + "keywords": [ + "rfc3986", + "uri", + "url" + ] + }, + { + "name": "sabre/vobject", + "version": "4.1.2", + "version_normalized": "4.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-vobject.git", + "reference": "d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c", + "reference": "d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.5", + "sabre/xml": ">=1.5 <3.0" + }, + "require-dev": { + "phpunit/phpunit": "*", + "sabre/cs": "^1.0.0" + }, + "suggest": { + "hoa/bench": "If you would like to run the benchmark scripts" + }, + "time": "2016-12-06 04:14:09", + "bin": [ + "bin/vobject", + "bin/generate_vcards" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Sabre\\VObject\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Dominik Tobschall", + "email": "dominik@fruux.com", + "homepage": "http://tobschall.de/", + "role": "Developer" + }, + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net", + "homepage": "http://mnt.io/", + "role": "Developer" + } + ], + "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", + "homepage": "http://sabre.io/vobject/", + "keywords": [ + "availability", + "freebusy", + "iCalendar", + "ical", + "ics", + "jCal", + "jCard", + "recurrence", + "rfc2425", + "rfc2426", + "rfc2739", + "rfc4770", + "rfc5545", + "rfc5546", + "rfc6321", + "rfc6350", + "rfc6351", + "rfc6474", + "rfc6638", + "rfc6715", + "rfc6868", + "vCalendar", + "vCard", + "vcf", + "xCal", + "xCard" + ] + }, + { + "name": "sabre/http", + "version": "4.2.2", + "version_normalized": "4.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-http.git", + "reference": "dd50e7260356f4599d40270826f9548b23efa204" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-http/zipball/dd50e7260356f4599d40270826f9548b23efa204", + "reference": "dd50e7260356f4599d40270826f9548b23efa204", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": ">=5.4", + "sabre/event": ">=1.0.0,<4.0.0", + "sabre/uri": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.3", + "sabre/cs": "~0.0.1" + }, + "suggest": { + "ext-curl": " to make http requests with the Client class" + }, + "time": "2017-01-02 19:38:42", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\HTTP\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "The sabre/http library provides utilities for dealing with http requests and responses. ", + "homepage": "https://github.com/fruux/sabre-http", + "keywords": [ + "http" + ] + }, + { + "name": "sabre/dav", + "version": "3.2.2", + "version_normalized": "3.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-dav.git", + "reference": "e987775e619728f12205606c9cc3ee565ffb1516" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516", + "reference": "e987775e619728f12205606c9cc3ee565ffb1516", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-dom": "*", + "ext-iconv": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "lib-libxml": ">=2.7.0", + "php": ">=5.5.0", + "psr/log": "^1.0", + "sabre/event": ">=2.0.0, <4.0.0", + "sabre/http": "^4.2.1", + "sabre/uri": "^1.0.1", + "sabre/vobject": "^4.1.0", + "sabre/xml": "^1.4.0" + }, + "require-dev": { + "evert/phpdoc-md": "~0.1.0", + "monolog/monolog": "^1.18", + "phpunit/phpunit": "> 4.8, <6.0.0", + "sabre/cs": "^1.0.0" + }, + "suggest": { + "ext-curl": "*", + "ext-pdo": "*" + }, + "time": "2017-02-15 03:06:08", + "bin": [ + "bin/sabredav", + "bin/naturalselection" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Sabre\\DAV\\": "lib/DAV/", + "Sabre\\DAVACL\\": "lib/DAVACL/", + "Sabre\\CalDAV\\": "lib/CalDAV/", + "Sabre\\CardDAV\\": "lib/CardDAV/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "WebDAV Framework for PHP", + "homepage": "http://sabre.io/", + "keywords": [ + "CalDAV", + "CardDAV", + "WebDAV", + "framework", + "iCalendar" + ] } ] diff --git a/vendor/sabre/dav/.travis.yml b/vendor/sabre/dav/.travis.yml index a9189c981..85637048a 100644 --- a/vendor/sabre/dav/.travis.yml +++ b/vendor/sabre/dav/.travis.yml @@ -2,7 +2,9 @@ language: php php: - 5.5 - 5.6 - - 7 + - 7.0 + - 7.1 + env: matrix: @@ -19,7 +21,6 @@ before_script: - mysql -e 'create database sabredav_test' - psql -c "create database sabredav_test" -U postgres - psql -c "create user sabredav with PASSWORD 'sabredav';GRANT ALL PRIVILEGES ON DATABASE sabredav_test TO sabredav" -U postgres - - phpenv config-rm xdebug.ini; true # - composer self-update - composer update --prefer-dist $LOWEST_DEPS @@ -28,7 +29,7 @@ before_script: script: - ./bin/phpunit --configuration tests/phpunit.xml.dist $TEST_DEPS - - ./bin/sabre-cs-fixer fix lib/ --dry-run --diff + - ./bin/sabre-cs-fixer fix . --dry-run --diff cache: directories: diff --git a/vendor/sabre/dav/CHANGELOG.md b/vendor/sabre/dav/CHANGELOG.md index d8a3898c3..0bccc995c 100644 --- a/vendor/sabre/dav/CHANGELOG.md +++ b/vendor/sabre/dav/CHANGELOG.md @@ -1,6 +1,28 @@ ChangeLog ========= +3.2.2 (2017-02-14) +------------------ + +* #943: Fix CardDAV XML reporting bug, which was affecting several CardDAV + clients. Bug was introduced in 3.2.1. +* The zip release ships with [sabre/vobject 4.1.2][vobj], + [sabre/http 4.2.2][http], [sabre/event 3.0.0][evnt], + [sabre/uri 1.2.0][uri] and [sabre/xml 1.5.0][xml]. + + +3.2.1 (2017-01-28) +------------------ + +* #877: Fix for syncing large calendars when using the Sqlite PDO backend. + (@theseer). +* #889 Added support for filtering vCard properties in the addressbook-query + REPORT (@DeepDiver1975). +* The zip release ships with [sabre/vobject 4.1.2][vobj], + [sabre/http 4.2.2][http], [sabre/event 3.0.0][evnt], + [sabre/uri 1.2.0][uri] and [sabre/xml 1.5.0][xml]. + + 3.2.0 (2016-06-27) ------------------ @@ -88,6 +110,9 @@ ChangeLog ------------------ * Fixed: Creating a new calendar on some MySQL configurations caused an error. +* #889 Added support for filtering vCard properties in the addressbook-query + REPORT (@DeepDiver1975). + 3.1.4 (2016-05-28) @@ -200,6 +225,13 @@ ChangeLog [sabre/uri 1.0.1][uri] and [sabre/xml 1.1.0][xml]. +3.0.10 (2016-??-??) +------------------ + +* #889 Added support for filtering vCard properties in the addressbook-query + REPORT (@DeepDiver1975). + + 3.0.9 (2016-04-06) ------------------ @@ -463,11 +495,13 @@ ChangeLog * #193: Fix `Sabre\DAV\FSExt\Directory::getQuotaInfo()` on windows. -2.1.11 (2016-??-??) +2.1.11 (2016-10-06) ------------------- * #805: It wasn't possible to create calendars that hold events, journals and todos using MySQL, because the `components` column was 1 byte too small. +* The zip release ships with [sabre/vobject 3.5.3][vobj], + [sabre/http 3.0.5][http], and [sabre/event 2.0.2][evnt]. 2.1.10 (2016-03-10) @@ -475,6 +509,8 @@ ChangeLog * #784: Sync logs for address books were not correctly cleaned up after deleting them. +* The zip release ships with [sabre/vobject 3.5.0][vobj], + [sabre/http 3.0.5][http], and [sabre/event 2.0.2][evnt]. 2.1.9 (2016-01-25) @@ -627,7 +663,7 @@ ChangeLog * Added: Automatically converting between vCard 3, 4 and jCard using the `Accept:` header, in CardDAV reports, and automatically converting from jCard to vCard upon `PUT`. It's important to note that your backends _may_ - now recieve both vCard 3.0 and 4.0. + now receive both vCard 3.0 and 4.0. * Added: #444. Collections can now opt-in to support high-speed `MOVE`. * Changed: PropertyStorage backends now have a `move` method. * Added: `beforeMove`, and `afterMove` events. @@ -812,7 +848,7 @@ ChangeLog * Added: Support for the `{DAV:}supported-method-set` property server-wide. * Making it easier for implementors to override how the CardDAV addressbook home is located. -* Fixed: Issue #422 Preconditions were not being set on PUT on non-existant +* Fixed: Issue #422 Preconditions were not being set on PUT on non-existent files. Not really a chance for data-loss, but incorrect nevertheless. * Fixed: Issue #428: Etag check with `If:` fails if the target is a collection. * Fixed: Issues #430, #431, #433: Locks plugin didn't not properly release @@ -1024,7 +1060,7 @@ ChangeLog * Added: Sharee's can now also read out the list of invites for a shared calendar. * Added: The Proxy principal classes now both implement an interface, for - greater flexiblity. + greater flexibility. 1.7.13 (2014-07-28) @@ -1042,7 +1078,7 @@ ChangeLog Sabre_DAV_PartialUpdate_IFile interface is now deprecated and will be removed in a future version. * Fixed: Restoring old setting after changing libxml_disable_entity_loader. -* Fixed: Issue #422: Preconditions were not being set on PUT on non-existant +* Fixed: Issue #422: Preconditions were not being set on PUT on non-existent files. Not really a chance for data-loss, but incorrect nevertheless. * Fixed: Issue #427: Now checking preconditions on DELETE requests. * Fixed: Issue #428: Etag check with If: fails if the target is a collection. @@ -1121,7 +1157,7 @@ ChangeLog ------------------ * The zip release ships with sabre/vobject 2.0.5. -* Changed: To be compatibile with MS Office 2011 for Mac, a workaround was +* Changed: To be compatible with MS Office 2011 for Mac, a workaround was removed that was added to support old versions of Windows XP (pre-SP3). Indeed! We needed a crazy workaround to work with one MS product in the past, and we can't keep that workaround to be compatible with another MS product. @@ -1129,7 +1165,7 @@ ChangeLog * Fixed: Range requests now work for non-seekable streams. (Thanks Alfred Klomp). * Fixed: Changed serialization of {DAV:}getlastmodified and {DAV:}supportedlock - to improve compatiblity with MS Office 2011 for Mac. + to improve compatibility with MS Office 2011 for Mac. * Changed: reverted the automatic translation of 'DAV:' xml namespaces to 'urn:DAV' when parsing files. Issues were reported with libxml 2.6.32, on a relatively recent debian release, so we'll wait till 2015 to take this one out @@ -2006,7 +2042,7 @@ ChangeLog ------------------- * Fixed: Issue 34: Invalid Lock-Token header response. -* Added: Issue 35: Addign SabreDAV version to HTTP OPTIONS responses. +* Added: Issue 35: Adding SabreDAV version to HTTP OPTIONS responses. 1.0.9 (2010-03-19) @@ -2220,7 +2256,7 @@ ChangeLog * Added: Simple HTML directory plugin, for browser access. * Added: Server class now sends back standard pre-condition error xml bodies. This was new since RFC4918. -* Added: Sabre_DAV_Tree_Aggregrate, which can 'host' multiple Tree objects into +* Added: Sabre_DAV_Tree_Aggregate, which can 'host' multiple Tree objects into one. * Added: simple basis for HTTP REPORT method. This method is not used yet, but can be used by plugins to add reports. @@ -2237,7 +2273,7 @@ ChangeLog 8.2. * Fixed: TemporaryFileFilter now lets through GET's if they actually exist on the backend. (r274) -* FIxed: Some methods didn't get passed through in the FilterTree (r283). +* Fixed: Some methods didn't get passed through in the FilterTree (r283). * Fixed: LockManager is now slightly more complex, Tree classes slightly less. (r287) diff --git a/vendor/sabre/dav/README.md b/vendor/sabre/dav/README.md index 8edcd4073..86a0fe9a6 100644 --- a/vendor/sabre/dav/README.md +++ b/vendor/sabre/dav/README.md @@ -10,6 +10,7 @@ Full documentation can be found on the website: http://sabre.io/ + Build status ------------ @@ -30,6 +31,7 @@ Documentation * [Introduction](http://sabre.io/dav/). * [Installation](http://sabre.io/dav/install/). + Made at fruux ------------- diff --git a/vendor/sabre/dav/bin/build.php b/vendor/sabre/dav/bin/build.php index c4ba20941..c4ba20941 100644..100755 --- a/vendor/sabre/dav/bin/build.php +++ b/vendor/sabre/dav/bin/build.php diff --git a/vendor/sabre/dav/bin/googlecode_upload.py b/vendor/sabre/dav/bin/googlecode_upload.py index caafd5ded..caafd5ded 100644..100755 --- a/vendor/sabre/dav/bin/googlecode_upload.py +++ b/vendor/sabre/dav/bin/googlecode_upload.py diff --git a/vendor/sabre/dav/bin/migrateto20.php b/vendor/sabre/dav/bin/migrateto20.php index 77236804f..77236804f 100644..100755 --- a/vendor/sabre/dav/bin/migrateto20.php +++ b/vendor/sabre/dav/bin/migrateto20.php diff --git a/vendor/sabre/dav/bin/migrateto21.php b/vendor/sabre/dav/bin/migrateto21.php index c81ee5cca..c81ee5cca 100644..100755 --- a/vendor/sabre/dav/bin/migrateto21.php +++ b/vendor/sabre/dav/bin/migrateto21.php diff --git a/vendor/sabre/dav/bin/migrateto30.php b/vendor/sabre/dav/bin/migrateto30.php index 9ca77c13c..9ca77c13c 100644..100755 --- a/vendor/sabre/dav/bin/migrateto30.php +++ b/vendor/sabre/dav/bin/migrateto30.php diff --git a/vendor/sabre/dav/bin/migrateto32.php b/vendor/sabre/dav/bin/migrateto32.php index 7567aeb60..7567aeb60 100644..100755 --- a/vendor/sabre/dav/bin/migrateto32.php +++ b/vendor/sabre/dav/bin/migrateto32.php diff --git a/vendor/sabre/dav/bin/sabredav.php b/vendor/sabre/dav/bin/sabredav.php index 950075d1a..950075d1a 100644..100755 --- a/vendor/sabre/dav/bin/sabredav.php +++ b/vendor/sabre/dav/bin/sabredav.php diff --git a/vendor/sabre/dav/composer.json b/vendor/sabre/dav/composer.json index f85d9655e..fca0e07fb 100644 --- a/vendor/sabre/dav/composer.json +++ b/vendor/sabre/dav/composer.json @@ -32,9 +32,9 @@ "psr/log": "^1.0" }, "require-dev" : { - "phpunit/phpunit" : "> 4.8, <=6.0.0", + "phpunit/phpunit" : "> 4.8, <6.0.0", "evert/phpdoc-md" : "~0.1.0", - "sabre/cs" : "~0.0.5", + "sabre/cs" : "^1.0.0", "monolog/monolog": "^1.18" }, "suggest" : { diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php b/vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php index d58b4a46e..311b1c415 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Backend; -use Sabre\VObject; use Sabre\CalDAV; +use Sabre\VObject; /** * Abstract Calendaring backend. Extend this class to create your own backends. @@ -26,9 +26,9 @@ abstract class AbstractBackend implements BackendInterface { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * - * @param string $path + * @param mixed $calendarId * @param \Sabre\DAV\PropPatch $propPatch * @return void */ diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php b/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php index 9c00a89ef..bf2ef27a0 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php @@ -49,8 +49,8 @@ interface NotificationSupport extends BackendInterface { * If the user chose to accept the share, this method should return the * newly created calendar url. * - * @param string href The sharee who is replying (often a mailto: address) - * @param int status One of the SharingPlugin::STATUS_* constants + * @param string $href The sharee who is replying (often a mailto: address) + * @param int $status One of the SharingPlugin::STATUS_* constants * @param string $calendarUri The url to the calendar thats being shared * @param string $inReplyTo The unique id this message is a response to * @param string $summary A description of the reply diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php b/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php index 95f1d49a6..458440588 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php @@ -5,8 +5,8 @@ namespace Sabre\CalDAV\Backend; use Sabre\CalDAV; use Sabre\DAV; use Sabre\DAV\Exception\Forbidden; -use Sabre\VObject; use Sabre\DAV\Xml\Element\Sharee; +use Sabre\VObject; /** * PDO CalDAV backend @@ -296,7 +296,7 @@ SQL * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param mixed $calendarId * @param \Sabre\DAV\PropPatch $propPatch @@ -481,13 +481,13 @@ SQL if (!$row) return null; return [ - 'id' => $row['id'], - 'uri' => $row['uri'], - 'lastmodified' => (int)$row['lastmodified'], - 'etag' => '"' . $row['etag'] . '"', - 'size' => (int)$row['size'], - 'calendardata' => $row['calendardata'], - 'component' => strtolower($row['componenttype']), + 'id' => $row['id'], + 'uri' => $row['uri'], + 'lastmodified' => (int)$row['lastmodified'], + 'etag' => '"' . $row['etag'] . '"', + 'size' => (int)$row['size'], + 'calendardata' => $row['calendardata'], + 'component' => strtolower($row['componenttype']), ]; } @@ -511,27 +511,29 @@ SQL } list($calendarId, $instanceId) = $calendarId; - $query = 'SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ? AND uri IN ('; - // Inserting a whole bunch of question marks - $query .= implode(',', array_fill(0, count($uris), '?')); - $query .= ')'; + $result = []; + foreach (array_chunk($uris, 900) as $chunk) { + $query = 'SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ? AND uri IN ('; + // Inserting a whole bunch of question marks + $query .= implode(',', array_fill(0, count($chunk), '?')); + $query .= ')'; - $stmt = $this->pdo->prepare($query); - $stmt->execute(array_merge([$calendarId], $uris)); + $stmt = $this->pdo->prepare($query); + $stmt->execute(array_merge([$calendarId], $chunk)); - $result = []; - while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { - $result[] = [ - 'id' => $row['id'], - 'uri' => $row['uri'], - 'lastmodified' => (int)$row['lastmodified'], - 'etag' => '"' . $row['etag'] . '"', - 'size' => (int)$row['size'], - 'calendardata' => $row['calendardata'], - 'component' => strtolower($row['componenttype']), - ]; + $result[] = [ + 'id' => $row['id'], + 'uri' => $row['uri'], + 'lastmodified' => (int)$row['lastmodified'], + 'etag' => '"' . $row['etag'] . '"', + 'size' => (int)$row['size'], + 'calendardata' => $row['calendardata'], + 'component' => strtolower($row['componenttype']), + ]; + } } return $result; @@ -686,7 +688,7 @@ SQL } } - + // Ensure Occurence values are positive if ($firstOccurence < 0) $firstOccurence = 0; if ($lastOccurence < 0) $lastOccurence = 0; @@ -769,7 +771,7 @@ SQL * Note that especially time-range-filters may be difficult to parse. A * time-range filter specified on a VEVENT must for instance also handle * recurrence rules correctly. - * A good example of how to interprete all these filters can also simply + * A good example of how to interpret all these filters can also simply * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct * as possible, so it gives you a good idea on what type of stuff you need * to think of. @@ -969,7 +971,7 @@ SQL; // Current synctoken $stmt = $this->pdo->prepare('SELECT synctoken FROM ' . $this->calendarTableName . ' WHERE id = ?'); - $stmt->execute([ $calendarId ]); + $stmt->execute([$calendarId]); $currentToken = $stmt->fetchColumn(0); if (is_null($currentToken)) return null; @@ -1181,7 +1183,7 @@ SQL; * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param mixed $subscriptionId * @param \Sabre\DAV\PropPatch $propPatch @@ -1327,7 +1329,7 @@ SQL; function createSchedulingObject($principalUri, $objectUri, $objectData) { $stmt = $this->pdo->prepare('INSERT INTO ' . $this->schedulingObjectTableName . ' (principaluri, calendardata, uri, lastmodified, etag, size) VALUES (?, ?, ?, ?, ?, ?)'); - $stmt->execute([$principalUri, $objectData, $objectUri, time(), md5($objectData), strlen($objectData) ]); + $stmt->execute([$principalUri, $objectData, $objectUri, time(), md5($objectData), strlen($objectData)]); } @@ -1483,7 +1485,7 @@ SQL; 'inviteStatus' => (int)$row['share_invitestatus'], 'properties' => !empty($row['share_displayname']) - ? [ '{DAV:}displayname' => $row['share_displayname'] ] + ? ['{DAV:}displayname' => $row['share_displayname']] : [], 'principal' => $row['principaluri'], ]); @@ -1502,7 +1504,7 @@ SQL; */ function setPublishStatus($calendarId, $value) { - throw new \Sabre\DAV\Exception\NotImplemented('Not implemented'); + throw new DAV\Exception\NotImplemented('Not implemented'); } diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php b/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php index 8b6e074e0..278ec2564 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php @@ -11,9 +11,9 @@ namespace Sabre\CalDAV\Backend; * 1. Return shared calendars for users. * 2. For every calendar, return calendar-resource-uri. This strings is a URI or * relative URI reference that must be unique for every calendar, but - * identical for every instance of the same shared calenar. - * 3. For every calenar, you must return a share-access element. This element - * should contain one of the Sabre\DAV\Sharing\Plugin:ACCESS_* contants and + * identical for every instance of the same shared calendar. + * 3. For every calendar, you must return a share-access element. This element + * should contain one of the Sabre\DAV\Sharing\Plugin:ACCESS_* constants and * indicates the access level the user has. * * @copyright Copyright (C) fruux GmbH (https://fruux.com/) diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php b/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php index f8238ea9a..d21f7f916 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php @@ -8,7 +8,7 @@ use Sabre\DAV; /** * Simple PDO CalDAV backend. * - * This class is basically the most minmum example to get a caldav backend up + * This class is basically the most minimum example to get a caldav backend up * and running. This class uses the following schema (MySQL example): * * CREATE TABLE simple_calendars ( @@ -209,12 +209,12 @@ class SimplePDO extends AbstractBackend { if (!$row) return null; return [ - 'id' => $row['id'], - 'uri' => $row['uri'], - 'etag' => '"' . md5($row['calendardata']) . '"', - 'calendarid' => $calendarId, - 'size' => strlen($row['calendardata']), - 'calendardata' => $row['calendardata'], + 'id' => $row['id'], + 'uri' => $row['uri'], + 'etag' => '"' . md5($row['calendardata']) . '"', + 'calendarid' => $calendarId, + 'size' => strlen($row['calendardata']), + 'calendardata' => $row['calendardata'], ]; } diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php b/vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php index a39289f5e..d77a2fe0f 100644 --- a/vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php +++ b/vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php @@ -70,7 +70,7 @@ interface SubscriptionSupport extends BackendInterface { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param mixed $subscriptionId * @param \Sabre\DAV\PropPatch $propPatch diff --git a/vendor/sabre/dav/lib/CalDAV/Calendar.php b/vendor/sabre/dav/lib/CalDAV/Calendar.php index 90ace0d21..7467900cc 100644 --- a/vendor/sabre/dav/lib/CalDAV/Calendar.php +++ b/vendor/sabre/dav/lib/CalDAV/Calendar.php @@ -3,8 +3,8 @@ namespace Sabre\CalDAV; use Sabre\DAV; -use Sabre\DAVACL; use Sabre\DAV\PropPatch; +use Sabre\DAVACL; /** * This object represents a CalDAV calendar. diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarHome.php b/vendor/sabre/dav/lib/CalDAV/CalendarHome.php index 0a4bfb68f..ffd7f72fb 100644 --- a/vendor/sabre/dav/lib/CalDAV/CalendarHome.php +++ b/vendor/sabre/dav/lib/CalDAV/CalendarHome.php @@ -27,7 +27,7 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL { /** * CalDAV backend * - * @var Sabre\CalDAV\Backend\BackendInterface + * @var Backend\BackendInterface */ protected $caldavBackend; @@ -42,7 +42,7 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL { * Constructor * * @param Backend\BackendInterface $caldavBackend - * @param mixed $userUri + * @param array $principalInfo */ function __construct(Backend\BackendInterface $caldavBackend, $principalInfo) { @@ -334,8 +334,8 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL { * This method should return the url of the newly created calendar if the * share was accepted. * - * @param string href The sharee who is replying (often a mailto: address) - * @param int status One of the SharingPlugin::STATUS_* constants + * @param string $href The sharee who is replying (often a mailto: address) + * @param int $status One of the SharingPlugin::STATUS_* constants * @param string $calendarUri The url to the calendar thats being shared * @param string $inReplyTo The unique id this message is a response to * @param string $summary A description of the reply diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarObject.php b/vendor/sabre/dav/lib/CalDAV/CalendarObject.php index 001b35112..9d6532a35 100644 --- a/vendor/sabre/dav/lib/CalDAV/CalendarObject.php +++ b/vendor/sabre/dav/lib/CalDAV/CalendarObject.php @@ -16,7 +16,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\ /** * Sabre\CalDAV\Backend\BackendInterface * - * @var Sabre\CalDAV\Backend\AbstractBackend + * @var Backend\AbstractBackend */ protected $caldavBackend; diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarQueryValidator.php b/vendor/sabre/dav/lib/CalDAV/CalendarQueryValidator.php index f3c7524d2..df8008fe2 100644 --- a/vendor/sabre/dav/lib/CalDAV/CalendarQueryValidator.php +++ b/vendor/sabre/dav/lib/CalDAV/CalendarQueryValidator.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV; -use Sabre\VObject; use DateTime; +use Sabre\VObject; /** * CalendarQuery Validator @@ -25,7 +25,7 @@ class CalendarQueryValidator { * * The list of filters must be formatted as parsed by \Sabre\CalDAV\CalendarQueryParser * - * @param VObject\Component $vObject + * @param VObject\Component\VCalendar $vObject * @param array $filters * @return bool */ diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarRoot.php b/vendor/sabre/dav/lib/CalDAV/CalendarRoot.php index 0ac50e41d..1d6b2ac9f 100644 --- a/vendor/sabre/dav/lib/CalDAV/CalendarRoot.php +++ b/vendor/sabre/dav/lib/CalDAV/CalendarRoot.php @@ -22,7 +22,7 @@ class CalendarRoot extends \Sabre\DAVACL\AbstractPrincipalCollection { /** * CalDAV backend * - * @var Sabre\CalDAV\Backend\BackendInterface + * @var Backend\BackendInterface */ protected $caldavBackend; diff --git a/vendor/sabre/dav/lib/CalDAV/Exception/InvalidComponentType.php b/vendor/sabre/dav/lib/CalDAV/Exception/InvalidComponentType.php index 5ce8a93f5..7aff2edab 100644 --- a/vendor/sabre/dav/lib/CalDAV/Exception/InvalidComponentType.php +++ b/vendor/sabre/dav/lib/CalDAV/Exception/InvalidComponentType.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Exception; -use Sabre\DAV; use Sabre\CalDAV; +use Sabre\DAV; /** * InvalidComponentType diff --git a/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php b/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php index a3a824c71..fc8b971f3 100644 --- a/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php +++ b/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php @@ -2,13 +2,13 @@ namespace Sabre\CalDAV; +use DateTime; use DateTimeZone; use Sabre\DAV; -use Sabre\VObject; +use Sabre\DAV\Exception\BadRequest; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; -use Sabre\DAV\Exception\BadRequest; -use DateTime; +use Sabre\VObject; /** * ICS Exporter diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php b/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php index 5fda61dfa..557832a5a 100644 --- a/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php +++ b/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Notifications; -use Sabre\DAV; use Sabre\CalDAV; +use Sabre\DAV; use Sabre\DAVACL; /** @@ -27,7 +27,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL { /** * The notification backend * - * @var Sabre\CalDAV\Backend\NotificationSupport + * @var CalDAV\Backend\NotificationSupport */ protected $caldavBackend; diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/INode.php b/vendor/sabre/dav/lib/CalDAV/Notifications/INode.php index f9986b714..783b92be9 100644 --- a/vendor/sabre/dav/lib/CalDAV/Notifications/INode.php +++ b/vendor/sabre/dav/lib/CalDAV/Notifications/INode.php @@ -2,6 +2,8 @@ namespace Sabre\CalDAV\Notifications; +use Sabre\CalDAV\Xml\Notification\NotificationInterface; + /** * This node represents a single notification. * @@ -20,16 +22,16 @@ interface INode { /** * This method must return an xml element, using the - * Sabre\CalDAV\Notifications\INotificationType classes. + * Sabre\CalDAV\Xml\Notification\NotificationInterface classes. * - * @return INotificationType + * @return NotificationInterface */ function getNotificationType(); /** * Returns the etag for the notification. * - * The etag must be surrounded by litteral double-quotes. + * The etag must be surrounded by literal double-quotes. * * @return string */ diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php b/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php index 11df0c94b..ad7ddf8f5 100644 --- a/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php +++ b/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php @@ -2,9 +2,9 @@ namespace Sabre\CalDAV\Notifications; -use Sabre\DAV; use Sabre\CalDAV; use Sabre\CalDAV\Xml\Notification\NotificationInterface; +use Sabre\DAV; use Sabre\DAVACL; /** @@ -25,14 +25,14 @@ class Node extends DAV\File implements INode, DAVACL\IACL { /** * The notification backend * - * @var Sabre\CalDAV\Backend\NotificationSupport + * @var CalDAV\Backend\NotificationSupport */ protected $caldavBackend; /** * The actual notification * - * @var Sabre\CalDAV\Notifications\INotificationType + * @var NotificationInterface */ protected $notification; @@ -61,7 +61,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL { /** * Returns the path name for this notification * - * @return id + * @return string */ function getName() { @@ -84,9 +84,9 @@ class Node extends DAV\File implements INode, DAVACL\IACL { /** * This method must return an xml element, using the - * Sabre\CalDAV\Notifications\INotificationType classes. + * Sabre\CalDAV\Xml\Notification\NotificationInterface classes. * - * @return INotificationType + * @return NotificationInterface */ function getNotificationType() { diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php index 546bf927f..e742351f5 100644 --- a/vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php +++ b/vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php @@ -3,10 +3,10 @@ namespace Sabre\CalDAV\Notifications; use Sabre\DAV; -use Sabre\DAV\PropFind; use Sabre\DAV\INode as BaseINode; -use Sabre\DAV\ServerPlugin; +use Sabre\DAV\PropFind; use Sabre\DAV\Server; +use Sabre\DAV\ServerPlugin; use Sabre\DAVACL; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; diff --git a/vendor/sabre/dav/lib/CalDAV/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Plugin.php index 71ba75206..def11d52d 100644 --- a/vendor/sabre/dav/lib/CalDAV/Plugin.php +++ b/vendor/sabre/dav/lib/CalDAV/Plugin.php @@ -9,11 +9,11 @@ use Sabre\DAV\INode; use Sabre\DAV\MkCol; use Sabre\DAV\Xml\Property\LocalHref; use Sabre\DAVACL; -use Sabre\VObject; use Sabre\HTTP; -use Sabre\Uri; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +use Sabre\Uri; +use Sabre\VObject; /** * CalDAV plugin @@ -302,8 +302,8 @@ class Plugin extends DAV\ServerPlugin { $this->server->createCollection($path, new MkCol($resourceType, $properties)); - $this->server->httpResponse->setStatus(201); - $this->server->httpResponse->setHeader('Content-Length', 0); + $response->setStatus(201); + $response->setHeader('Content-Length', 0); // This breaks the method chain. return false; @@ -926,7 +926,7 @@ class Plugin extends DAV\ServerPlugin { ); } - // We use an extra variable to allow event handles to tell us wether + // We use an extra variable to allow event handles to tell us whether // the object was modified or not. // // This helps us determine if we need to re-serialize the object. diff --git a/vendor/sabre/dav/lib/CalDAV/Principal/ProxyRead.php b/vendor/sabre/dav/lib/CalDAV/Principal/ProxyRead.php index 93f0fe095..e3881831e 100644 --- a/vendor/sabre/dav/lib/CalDAV/Principal/ProxyRead.php +++ b/vendor/sabre/dav/lib/CalDAV/Principal/ProxyRead.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Principal; -use Sabre\DAVACL; use Sabre\DAV; +use Sabre\DAVACL; /** * ProxyRead principal @@ -84,8 +84,8 @@ class ProxyRead implements IProxyRead { /** * Renames the node * - * @throws DAV\Exception\Forbidden * @param string $name The new name + * @throws DAV\Exception\Forbidden * @return void */ function setName($name) { diff --git a/vendor/sabre/dav/lib/CalDAV/Principal/ProxyWrite.php b/vendor/sabre/dav/lib/CalDAV/Principal/ProxyWrite.php index 8124c05e0..43dd9bf07 100644 --- a/vendor/sabre/dav/lib/CalDAV/Principal/ProxyWrite.php +++ b/vendor/sabre/dav/lib/CalDAV/Principal/ProxyWrite.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Principal; -use Sabre\DAVACL; use Sabre\DAV; +use Sabre\DAVACL; /** * ProxyWrite principal @@ -84,8 +84,8 @@ class ProxyWrite implements IProxyWrite { /** * Renames the node * - * @throws DAV\Exception\Forbidden * @param string $name The new name + * @throws DAV\Exception\Forbidden * @return void */ function setName($name) { diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php b/vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php index ffb1fe45b..6f5acb29a 100644 --- a/vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php +++ b/vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php @@ -181,7 +181,7 @@ class IMipPlugin extends DAV\ServerPlugin { return [ 'name' => $this->getPluginName(), - 'description' => 'Email delivery (rfc6037) for CalDAV scheduling', + 'description' => 'Email delivery (rfc6047) for CalDAV scheduling', 'link' => 'http://sabre.io/dav/scheduling/', ]; diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php index 6b374ea3f..81b017307 100644 --- a/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php +++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php @@ -2,10 +2,10 @@ namespace Sabre\CalDAV\Schedule; -use Sabre\DAV; use Sabre\CalDAV; -use Sabre\DAVACL; use Sabre\CalDAV\Backend; +use Sabre\DAV; +use Sabre\DAVACL; use Sabre\VObject; /** @@ -83,7 +83,7 @@ class Inbox extends DAV\Collection implements IInbox { * Data will either be supplied as a stream resource, or in certain cases * as a string. Keep in mind that you may have to support either. * - * After succesful creation of the file, you may choose to return the ETag + * After successful creation of the file, you may choose to return the ETag * of the new file here. * * The returned ETag must be surrounded by double-quotes (The quotes should diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php index 29eefa744..888ea3086 100644 --- a/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php +++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Schedule; -use Sabre\DAV; use Sabre\CalDAV; +use Sabre\DAV; use Sabre\DAVACL; /** diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php index 47511140f..0b991e619 100644 --- a/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php +++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php @@ -3,29 +3,28 @@ namespace Sabre\CalDAV\Schedule; use DateTimeZone; +use Sabre\CalDAV\ICalendar; +use Sabre\CalDAV\ICalendarObject; +use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\NotImplemented; +use Sabre\DAV\INode; +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; use Sabre\DAV\Sharing; -use Sabre\DAV\PropFind; -use Sabre\DAV\PropPatch; -use Sabre\DAV\INode; -use Sabre\DAV\Xml\Property\Href; use Sabre\DAV\Xml\Property\LocalHref; +use Sabre\DAVACL; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; use Sabre\VObject; -use Sabre\VObject\Reader; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\ITip; use Sabre\VObject\ITip\Message; -use Sabre\DAVACL; -use Sabre\CalDAV\ICalendar; -use Sabre\CalDAV\ICalendarObject; -use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\BadRequest; -use Sabre\DAV\Exception\NotImplemented; +use Sabre\VObject\Reader; /** * CalDAV scheduling plugin. @@ -377,7 +376,7 @@ class Plugin extends ServerPlugin { /** * This method is responsible for delivering the ITip message. * - * @param ITip\Message $itipMessage + * @param ITip\Message $iTipMessage * @return void */ function deliver(ITip\Message $iTipMessage) { @@ -890,8 +889,8 @@ class Plugin extends ServerPlugin { * * 3.7;description * * @param string $email address - * @param DateTimeInterface $start - * @param DateTimeInterface $end + * @param \DateTimeInterface $start + * @param \DateTimeInterface $end * @param VObject\Component $request * @return array */ @@ -1059,7 +1058,7 @@ class Plugin extends ServerPlugin { return [ 'name' => $this->getPluginName(), - 'description' => 'Adds calendar-auto-schedule, as defined in rf6868', + 'description' => 'Adds calendar-auto-schedule, as defined in rfc6638', 'link' => 'http://sabre.io/dav/scheduling/', ]; diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php b/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php index 6d9d3d5ec..0cd05a965 100644 --- a/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php +++ b/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php @@ -42,7 +42,7 @@ class SchedulingObject extends \Sabre\CalDAV\CalendarObject implements IScheduli * * lastmodified - (optional) format as a unix timestamp. * * acl - (optional) Use this to override the default ACL for the node. * - * @param Backend\BackendInterface $caldavBackend + * @param Backend\SchedulingSupport $caldavBackend * @param array $objectData */ function __construct(Backend\SchedulingSupport $caldavBackend, array $objectData) { diff --git a/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php b/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php index 6f7df02bc..5cce79678 100644 --- a/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php +++ b/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php @@ -3,7 +3,6 @@ namespace Sabre\CalDAV; use Sabre\DAV; -use Sabre\DAV\Xml\Property\Href; use Sabre\DAV\Xml\Property\LocalHref; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -29,7 +28,7 @@ class SharingPlugin extends DAV\ServerPlugin { /** * Reference to SabreDAV server object. * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php index 7abbfb1f9..877d96c6c 100644 --- a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php +++ b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php @@ -4,8 +4,8 @@ namespace Sabre\CalDAV\Subscriptions; use Sabre\DAV\INode; use Sabre\DAV\PropFind; -use Sabre\DAV\ServerPlugin; use Sabre\DAV\Server; +use Sabre\DAV\ServerPlugin; /** * This plugin adds calendar-subscription support to your CalDAV server. diff --git a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php index 3bb3451f3..6a1851ed8 100644 --- a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php +++ b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php @@ -2,12 +2,12 @@ namespace Sabre\CalDAV\Subscriptions; +use Sabre\CalDAV\Backend\SubscriptionSupport; use Sabre\DAV\Collection; -use Sabre\DAV\Xml\Property\Href; use Sabre\DAV\PropPatch; -use Sabre\DAVACL\IACL; +use Sabre\DAV\Xml\Property\Href; use Sabre\DAVACL\ACLTrait; -use Sabre\CalDAV\Backend\SubscriptionSupport; +use Sabre\DAVACL\IACL; /** * Subscription Node @@ -25,7 +25,7 @@ class Subscription extends Collection implements ISubscription, IACL { /** * caldavBackend * - * @var SupportsSubscriptions + * @var SubscriptionSupport */ protected $caldavBackend; @@ -40,7 +40,7 @@ class Subscription extends Collection implements ISubscription, IACL { * Constructor * * @param SubscriptionSupport $caldavBackend - * @param array $calendarInfo + * @param array $subscriptionInfo */ function __construct(SubscriptionSupport $caldavBackend, array $subscriptionInfo) { @@ -104,7 +104,7 @@ class Subscription extends Collection implements ISubscription, IACL { /** * Returns an array with all the child nodes * - * @return DAV\INode[] + * @return \Sabre\DAV\INode[] */ function getChildren() { diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php index 9babcf15c..9669be304 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV\Xml\Filter; -use Sabre\Xml\Reader; -use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; use Sabre\CalDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\VObject\DateTimeParser; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * CalendarData parser. @@ -30,7 +30,7 @@ class CalendarData implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php index c9b27dbfd..c21ede66b 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV\Xml\Filter; -use Sabre\Xml\Reader; -use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; use Sabre\CalDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\VObject\DateTimeParser; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * CompFilter parser. @@ -27,7 +27,7 @@ class CompFilter implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php index eb7f564df..bf422cf05 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php @@ -2,9 +2,9 @@ namespace Sabre\CalDAV\Xml\Filter; +use Sabre\CalDAV\Plugin; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\CalDAV\Plugin; /** * PropFilter parser. @@ -25,7 +25,7 @@ class ParamFilter implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php index 4c2e1b172..db9207295 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV\Xml\Filter; -use Sabre\Xml\Reader; -use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; use Sabre\CalDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\VObject\DateTimeParser; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * PropFilter parser. @@ -27,7 +27,7 @@ class PropFilter implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php index 1ca64f3e8..92a9ac7b7 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php @@ -2,10 +2,10 @@ namespace Sabre\CalDAV\Xml\Notification; -use Sabre\Xml\Writer; -use Sabre\CalDAV\SharingPlugin as SharingPlugin; use Sabre\CalDAV; +use Sabre\CalDAV\SharingPlugin as SharingPlugin; use Sabre\DAV; +use Sabre\Xml\Writer; /** * This class represents the cs:invite-notification notification element. @@ -107,7 +107,7 @@ class Invite implements NotificationInterface { /** * The list of supported components * - * @var Sabre\CalDAV\Property\SupportedCalendarComponentSet + * @var CalDAV\Xml\Property\SupportedCalendarComponentSet */ protected $supportedComponents; @@ -166,12 +166,12 @@ class Invite implements NotificationInterface { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php index 51bfc178a..f4b10a396 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php @@ -2,10 +2,10 @@ namespace Sabre\CalDAV\Xml\Notification; -use Sabre\Xml\Writer; use Sabre\CalDAV; use Sabre\CalDAV\SharingPlugin; use Sabre\DAV; +use Sabre\Xml\Writer; /** * This class represents the cs:invite-reply notification element. @@ -117,12 +117,12 @@ class InviteReply implements NotificationInterface { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/NotificationInterface.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/NotificationInterface.php index 1c08f12fd..b98f9c888 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/NotificationInterface.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/NotificationInterface.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Xml\Notification; -use Sabre\Xml\XmlSerializable; use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * This interface reflects a single notification type. diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/SystemStatus.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/SystemStatus.php index d41702e07..8c945dd68 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/SystemStatus.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/SystemStatus.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Xml\Notification; -use Sabre\Xml\Writer; use Sabre\CalDAV\Plugin; +use Sabre\Xml\Writer; /** * SystemStatus notification diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/AllowedSharingModes.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/AllowedSharingModes.php index c2a2d565e..54e5a116a 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/AllowedSharingModes.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/AllowedSharingModes.php @@ -2,9 +2,9 @@ namespace Sabre\CalDAV\Xml\Property; -use Sabre\Xml\XmlSerializable; -use Sabre\Xml\Writer; use Sabre\CalDAV\Plugin; +use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * AllowedSharingModes @@ -53,12 +53,12 @@ class AllowedSharingModes implements XmlSerializable { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/EmailAddressSet.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/EmailAddressSet.php index f577a9919..fc6f1d505 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/EmailAddressSet.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/EmailAddressSet.php @@ -49,12 +49,12 @@ class EmailAddressSet implements XmlSerializable { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php index 40ff6b936..4f33c464c 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php @@ -2,10 +2,11 @@ namespace Sabre\CalDAV\Xml\Property; -use Sabre\Xml\XmlSerializable; -use Sabre\Xml\Writer; use Sabre\CalDAV\Plugin; use Sabre\DAV; +use Sabre\DAV\Xml\Element\Sharee; +use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * Invite property @@ -51,12 +52,12 @@ class Invite implements XmlSerializable { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -75,7 +76,7 @@ class Invite implements XmlSerializable { foreach ($this->sharees as $sharee) { - if ($sharee->access === \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER) { + if ($sharee->access === DAV\Sharing\Plugin::ACCESS_SHAREDOWNER) { $writer->startElement($cs . 'organizer'); } else { $writer->startElement($cs . 'user'); @@ -109,7 +110,7 @@ class Invite implements XmlSerializable { } - $href = new \Sabre\DAV\Xml\Property\Href($sharee->href); + $href = new DAV\Xml\Property\Href($sharee->href); $href->xmlSerialize($writer); if (isset($sharee->properties['{DAV:}displayname'])) { diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php index a82b8eff7..10c20be55 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV\Xml\Property; +use Sabre\CalDAV\Plugin; +use Sabre\Xml\Deserializer; use Sabre\Xml\Element; use Sabre\Xml\Reader; -use Sabre\Xml\Deserializer; use Sabre\Xml\Writer; -use Sabre\CalDAV\Plugin; /** * schedule-calendar-transp property. @@ -62,12 +62,12 @@ class ScheduleCalendarTransp implements Element { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -96,7 +96,7 @@ class ScheduleCalendarTransp implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarComponentSet.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarComponentSet.php index 7a26e767e..7fc25c5f0 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarComponentSet.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarComponentSet.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV\Xml\Property; +use Sabre\CalDAV\Plugin; use Sabre\Xml\Element; use Sabre\Xml\ParseException; use Sabre\Xml\Reader; use Sabre\Xml\Writer; -use Sabre\CalDAV\Plugin; /** * SupportedCalendarComponentSet property. @@ -55,12 +55,12 @@ class SupportedCalendarComponentSet implements Element { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -88,7 +88,7 @@ class SupportedCalendarComponentSet implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarData.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarData.php index b0c407fd6..d123ba4c0 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarData.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCalendarData.php @@ -2,9 +2,9 @@ namespace Sabre\CalDAV\Xml\Property; -use Sabre\Xml\XmlSerializable; -use Sabre\Xml\Writer; use Sabre\CalDAV\Plugin; +use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * Supported-calendar-data property @@ -23,12 +23,12 @@ use Sabre\CalDAV\Plugin; class SupportedCalendarData implements XmlSerializable { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCollationSet.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCollationSet.php index 71de25a62..af10860d0 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCollationSet.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/SupportedCollationSet.php @@ -2,9 +2,9 @@ namespace Sabre\CalDAV\Xml\Property; +use Sabre\CalDAV\Plugin; use Sabre\Xml\Writer; use Sabre\Xml\XmlSerializable; -use Sabre\CalDAV\Plugin; /** * supported-collation-set property @@ -22,12 +22,12 @@ use Sabre\CalDAV\Plugin; class SupportedCollationSet implements XmlSerializable { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarMultiGetReport.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarMultiGetReport.php index 79b3bb3ac..6d3c5d508 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarMultiGetReport.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarMultiGetReport.php @@ -2,10 +2,10 @@ namespace Sabre\CalDAV\Xml\Request; -use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Reader; use Sabre\CalDAV\Plugin; use Sabre\Uri; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * CalendarMultiGetReport request parser. @@ -64,7 +64,7 @@ class CalendarMultiGetReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarQueryReport.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarQueryReport.php index 848a4dc46..e0b1c7950 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarQueryReport.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/CalendarQueryReport.php @@ -2,10 +2,10 @@ namespace Sabre\CalDAV\Xml\Request; -use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Reader; -use Sabre\DAV\Exception\BadRequest; use Sabre\CalDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * CalendarQueryReport request parser. @@ -64,7 +64,7 @@ class CalendarQueryReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/FreeBusyQueryReport.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/FreeBusyQueryReport.php index e3b27d08e..0f6c1e074 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/FreeBusyQueryReport.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/FreeBusyQueryReport.php @@ -38,7 +38,7 @@ class FreeBusyQueryReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php index 2ecf6c2bb..db32cc6a5 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php @@ -6,9 +6,9 @@ use Sabre\CalDAV\Plugin; use Sabre\CalDAV\SharingPlugin; use Sabre\DAV; use Sabre\DAV\Exception\BadRequest; +use Sabre\Xml\Element\KeyValue; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Element\KeyValue; /** * Invite-reply POST request parser @@ -82,7 +82,7 @@ class InviteReply implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/MkCalendar.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/MkCalendar.php index 7b745db55..ce7fafde9 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/MkCalendar.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/MkCalendar.php @@ -39,7 +39,7 @@ class MkCalendar implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -62,8 +62,8 @@ class MkCalendar implements XmlDeserializable { $self = new self(); $elementMap = $reader->elementMap; - $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; - $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; + $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; + $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; $elems = $reader->parseInnerTree($elementMap); foreach ($elems as $elem) { diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php index b5d9a133c..e0bd8e0af 100644 --- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php +++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php @@ -41,7 +41,7 @@ class Share implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CardDAV/AddressBook.php b/vendor/sabre/dav/lib/CardDAV/AddressBook.php index 6dd098618..c9d28a091 100644 --- a/vendor/sabre/dav/lib/CardDAV/AddressBook.php +++ b/vendor/sabre/dav/lib/CardDAV/AddressBook.php @@ -60,7 +60,7 @@ class AddressBook extends DAV\Collection implements IAddressBook, DAV\IPropertie * Returns a card * * @param string $name - * @return \ICard + * @return Card */ function getChild($name) { diff --git a/vendor/sabre/dav/lib/CardDAV/AddressBookHome.php b/vendor/sabre/dav/lib/CardDAV/AddressBookHome.php index 888a44a40..d770c0ffe 100644 --- a/vendor/sabre/dav/lib/CardDAV/AddressBookHome.php +++ b/vendor/sabre/dav/lib/CardDAV/AddressBookHome.php @@ -127,7 +127,7 @@ class AddressBookHome extends DAV\Collection implements DAV\IExtendedCollection, * * @param string $name * @todo needs optimizing - * @return \AddressBook + * @return AddressBook */ function getChild($name) { diff --git a/vendor/sabre/dav/lib/CardDAV/AddressBookRoot.php b/vendor/sabre/dav/lib/CardDAV/AddressBookRoot.php index 4a33df4ec..a9f1183da 100644 --- a/vendor/sabre/dav/lib/CardDAV/AddressBookRoot.php +++ b/vendor/sabre/dav/lib/CardDAV/AddressBookRoot.php @@ -18,7 +18,7 @@ class AddressBookRoot extends DAVACL\AbstractPrincipalCollection { /** * Principal Backend * - * @var Sabre\DAVACL\PrincipalBackend\BackendInteface + * @var DAVACL\PrincipalBackend\BackendInterface */ protected $principalBackend; diff --git a/vendor/sabre/dav/lib/CardDAV/Backend/BackendInterface.php b/vendor/sabre/dav/lib/CardDAV/Backend/BackendInterface.php index 54e42b899..18c0c0a99 100644 --- a/vendor/sabre/dav/lib/CardDAV/Backend/BackendInterface.php +++ b/vendor/sabre/dav/lib/CardDAV/Backend/BackendInterface.php @@ -46,7 +46,7 @@ interface BackendInterface { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $addressBookId * @param \Sabre\DAV\PropPatch $propPatch diff --git a/vendor/sabre/dav/lib/CardDAV/Backend/PDO.php b/vendor/sabre/dav/lib/CardDAV/Backend/PDO.php index 7c3feff93..13487e9da 100644 --- a/vendor/sabre/dav/lib/CardDAV/Backend/PDO.php +++ b/vendor/sabre/dav/lib/CardDAV/Backend/PDO.php @@ -93,7 +93,7 @@ class PDO extends AbstractBackend implements SyncSupport { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $addressBookId * @param \Sabre\DAV\PropPatch $propPatch @@ -240,7 +240,7 @@ class PDO extends AbstractBackend implements SyncSupport { } /** - * Returns a specfic card. + * Returns a specific card. * * The same set of properties must be returned as with getCards. The only * exception is that 'carddata' is absolutely required. @@ -466,7 +466,7 @@ class PDO extends AbstractBackend implements SyncSupport { // Current synctoken $stmt = $this->pdo->prepare('SELECT synctoken FROM ' . $this->addressBooksTableName . ' WHERE id = ?'); - $stmt->execute([ $addressBookId ]); + $stmt->execute([$addressBookId]); $currentToken = $stmt->fetchColumn(0); if (is_null($currentToken)) return null; diff --git a/vendor/sabre/dav/lib/CardDAV/Card.php b/vendor/sabre/dav/lib/CardDAV/Card.php index 0a040be6b..42a2d7b6a 100644 --- a/vendor/sabre/dav/lib/CardDAV/Card.php +++ b/vendor/sabre/dav/lib/CardDAV/Card.php @@ -2,8 +2,8 @@ namespace Sabre\CardDAV; -use Sabre\DAVACL; use Sabre\DAV; +use Sabre\DAVACL; /** * The Card object represents a single Card from an addressbook diff --git a/vendor/sabre/dav/lib/CardDAV/Plugin.php b/vendor/sabre/dav/lib/CardDAV/Plugin.php index 0507df100..272ae71fa 100644 --- a/vendor/sabre/dav/lib/CardDAV/Plugin.php +++ b/vendor/sabre/dav/lib/CardDAV/Plugin.php @@ -43,7 +43,7 @@ class Plugin extends DAV\ServerPlugin { /** * Server class * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; @@ -490,7 +490,8 @@ class Plugin extends DAV\ServerPlugin { $props[200]['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard( $props[200]['{' . self::NS_CARDDAV . '}address-data'], - $vcardType + $vcardType, + $report->addressDataProperties ); } @@ -845,14 +846,26 @@ class Plugin extends DAV\ServerPlugin { * * @param string|resource $data * @param string $target + * @param array $propertiesFilter * @return string */ - protected function convertVCard($data, $target) { + protected function convertVCard($data, $target, array $propertiesFilter = null) { if (is_resource($data)) { $data = stream_get_contents($data); } $input = VObject\Reader::read($data); + if (!empty($propertiesFilter)) { + $propertiesFilter = array_merge(['UID', 'VERSION', 'FN'], $propertiesFilter); + $keys = array_unique(array_map(function($child) { + return $child->name; + }, $input->children())); + $keys = array_diff($keys, $propertiesFilter); + foreach ($keys as $key) { + unset($input->$key); + } + $data = $input->serialize(); + } $output = null; try { diff --git a/vendor/sabre/dav/lib/CardDAV/VCFExportPlugin.php b/vendor/sabre/dav/lib/CardDAV/VCFExportPlugin.php index d015589ad..2d61db6ac 100644 --- a/vendor/sabre/dav/lib/CardDAV/VCFExportPlugin.php +++ b/vendor/sabre/dav/lib/CardDAV/VCFExportPlugin.php @@ -3,9 +3,9 @@ namespace Sabre\CardDAV; use Sabre\DAV; -use Sabre\VObject; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +use Sabre\VObject; /** * VCF Exporter @@ -24,7 +24,7 @@ class VCFExportPlugin extends DAV\ServerPlugin { /** * Reference to Server class * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/AddressData.php b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/AddressData.php index 34028db85..a130cd61d 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/AddressData.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/AddressData.php @@ -26,7 +26,7 @@ class AddressData implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -51,7 +51,11 @@ class AddressData implements XmlDeserializable { 'version' => $reader->getAttribute('version') ?: '3.0', ]; - $reader->next(); + $elems = (array)$reader->parseInnerTree(); + $result['addressDataProperties'] = array_map(function($element) { + return $element['attributes']['name']; + }, $elems); + return $result; } diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/ParamFilter.php b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/ParamFilter.php index 9646ae3e6..936e26917 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/ParamFilter.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/ParamFilter.php @@ -2,10 +2,10 @@ namespace Sabre\CardDAV\Xml\Filter; +use Sabre\CardDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\Xml\Element; use Sabre\Xml\Reader; -use Sabre\DAV\Exception\BadRequest; -use Sabre\CardDAV\Plugin; /** * ParamFilter parser. @@ -26,7 +26,7 @@ abstract class ParamFilter implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/PropFilter.php b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/PropFilter.php index c162da160..d7799429d 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Filter/PropFilter.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Filter/PropFilter.php @@ -2,10 +2,10 @@ namespace Sabre\CardDAV\Xml\Filter; +use Sabre\CardDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; -use Sabre\CardDAV\Plugin; /** * PropFilter parser. @@ -26,7 +26,7 @@ class PropFilter implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedAddressData.php b/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedAddressData.php index 6ff57b6e3..aecd8a09f 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedAddressData.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedAddressData.php @@ -2,9 +2,9 @@ namespace Sabre\CardDAV\Xml\Property; +use Sabre\CardDAV\Plugin; use Sabre\Xml\Writer; use Sabre\Xml\XmlSerializable; -use Sabre\CardDAV\Plugin; /** * Supported-address-data property @@ -49,12 +49,12 @@ class SupportedAddressData implements XmlSerializable { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedCollationSet.php b/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedCollationSet.php index 1fc064900..778aa2b64 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedCollationSet.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Property/SupportedCollationSet.php @@ -18,12 +18,12 @@ use Sabre\Xml\XmlSerializable; class SupportedCollationSet implements XmlSerializable { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookMultiGetReport.php b/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookMultiGetReport.php index c97c5eb4f..0115a0107 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookMultiGetReport.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookMultiGetReport.php @@ -54,7 +54,7 @@ class AddressBookMultiGetReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookQueryReport.php b/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookQueryReport.php index a68ac5800..09fad008a 100644 --- a/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookQueryReport.php +++ b/vendor/sabre/dav/lib/CardDAV/Xml/Request/AddressBookQueryReport.php @@ -2,10 +2,10 @@ namespace Sabre\CardDAV\Xml\Request; +use Sabre\CardDAV\Plugin; +use Sabre\DAV\Exception\BadRequest; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; -use Sabre\CardDAV\Plugin; /** * AddressBookQueryReport request parser. @@ -29,6 +29,13 @@ class AddressBookQueryReport implements XmlDeserializable { public $properties; /** + * An array with requested vcard properties. + * + * @var array + */ + public $addressDataProperties = []; + + /** * List of property/component filters. * * This is an array with filters. Every item is a property filter. Every @@ -92,7 +99,7 @@ class AddressBookQueryReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Auth/Backend/AbstractDigest.php b/vendor/sabre/dav/lib/DAV/Auth/Backend/AbstractDigest.php index 85c5f30d5..4b47f56c9 100644 --- a/vendor/sabre/dav/lib/DAV/Auth/Backend/AbstractDigest.php +++ b/vendor/sabre/dav/lib/DAV/Auth/Backend/AbstractDigest.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Auth\Backend; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; diff --git a/vendor/sabre/dav/lib/DAV/Auth/Backend/PDO.php b/vendor/sabre/dav/lib/DAV/Auth/Backend/PDO.php index 76ad89391..c2f6de974 100644 --- a/vendor/sabre/dav/lib/DAV/Auth/Backend/PDO.php +++ b/vendor/sabre/dav/lib/DAV/Auth/Backend/PDO.php @@ -31,7 +31,7 @@ class PDO extends AbstractDigest { * * If the filename argument is passed in, it will parse out the specified file fist. * - * @param PDO $pdo + * @param \PDO $pdo */ function __construct(\PDO $pdo) { diff --git a/vendor/sabre/dav/lib/DAV/Auth/Plugin.php b/vendor/sabre/dav/lib/DAV/Auth/Plugin.php index 4b5f35ac3..bbb5d180d 100644 --- a/vendor/sabre/dav/lib/DAV/Auth/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Auth/Plugin.php @@ -2,11 +2,11 @@ namespace Sabre\DAV\Auth; -use Sabre\HTTP\RequestInterface; -use Sabre\HTTP\ResponseInterface; use Sabre\DAV\Exception\NotAuthenticated; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; /** * This plugin provides Authentication for a WebDAV server. @@ -181,7 +181,7 @@ class Plugin extends ServerPlugin { * * If login was not successful, the second item in the array will contain a * an array with strings. The strings are a list of reasons why login was - * unsuccesful. For every auth backend there will be one reason, so usually + * unsuccessful. For every auth backend there will be one reason, so usually * there's just one. * * @param RequestInterface $request diff --git a/vendor/sabre/dav/lib/DAV/Browser/GuessContentType.php b/vendor/sabre/dav/lib/DAV/Browser/GuessContentType.php index 01cddc230..3ba2aee25 100644 --- a/vendor/sabre/dav/lib/DAV/Browser/GuessContentType.php +++ b/vendor/sabre/dav/lib/DAV/Browser/GuessContentType.php @@ -2,10 +2,10 @@ namespace Sabre\DAV\Browser; -use Sabre\HTTP\URLUtil; use Sabre\DAV; -use Sabre\DAV\PropFind; use Sabre\DAV\Inode; +use Sabre\DAV\PropFind; +use Sabre\HTTP\URLUtil; /** * GuessContentType plugin diff --git a/vendor/sabre/dav/lib/DAV/Browser/MapGetToPropFind.php b/vendor/sabre/dav/lib/DAV/Browser/MapGetToPropFind.php index 38ee63bcd..61327c49a 100644 --- a/vendor/sabre/dav/lib/DAV/Browser/MapGetToPropFind.php +++ b/vendor/sabre/dav/lib/DAV/Browser/MapGetToPropFind.php @@ -21,7 +21,7 @@ class MapGetToPropFind extends DAV\ServerPlugin { /** * reference to server class * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/lib/DAV/Browser/Plugin.php b/vendor/sabre/dav/lib/DAV/Browser/Plugin.php index 49359a045..545ad5633 100644 --- a/vendor/sabre/dav/lib/DAV/Browser/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Browser/Plugin.php @@ -4,9 +4,9 @@ namespace Sabre\DAV\Browser; use Sabre\DAV; use Sabre\DAV\MkCol; -use Sabre\HTTP\URLUtil; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +use Sabre\HTTP\URLUtil; /** * Browser Plugin @@ -26,7 +26,7 @@ class Plugin extends DAV\ServerPlugin { /** * reference to server class * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; @@ -112,7 +112,7 @@ class Plugin extends DAV\ServerPlugin { $getVars = $request->getQueryParameters(); // CSP headers - $this->server->httpResponse->setHeader('Content-Security-Policy', "default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"); + $response->setHeader('Content-Security-Policy', "default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"); $sabreAction = isset($getVars['sabreAction']) ? $getVars['sabreAction'] : null; @@ -317,7 +317,7 @@ class Plugin extends DAV\ServerPlugin { $buttonActions = ''; if ($subProps['subNode'] instanceof DAV\IFile) { - $buttonActions = '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>'; + $buttonActions = '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>'; } $this->server->emit('browserButtonActions', [$subProps['fullPath'], $subProps['subNode'], &$buttonActions]); @@ -414,11 +414,14 @@ class Plugin extends DAV\ServerPlugin { * * @param string $title * @param string $path - * @return void + * @return string */ function generateHeader($title, $path = null) { - $version = DAV\Version::VERSION; + $version = ''; + if (DAV\Server::$exposeVersion) { + $version = DAV\Version::VERSION; + } $vars = [ 'title' => $this->escapeHTML($title), @@ -475,7 +478,10 @@ HTML; */ function generateFooter() { - $version = DAV\Version::VERSION; + $version = ''; + if (DAV\Server::$exposeVersion) { + $version = DAV\Version::VERSION; + } return <<<HTML <footer>Generated by SabreDAV $version (c)2007-2016 <a href="http://sabre.io/">http://sabre.io/</a></footer> </body> @@ -506,23 +512,21 @@ HTML; if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') return; - ob_start(); - echo '<form method="post" action=""> - <h3>Create new folder</h3> - <input type="hidden" name="sabreAction" value="mkcol" /> - <label>Name:</label> <input type="text" name="name" /><br /> - <input type="submit" value="create" /> - </form> - <form method="post" action="" enctype="multipart/form-data"> - <h3>Upload file</h3> - <input type="hidden" name="sabreAction" value="put" /> - <label>Name (optional):</label> <input type="text" name="name" /><br /> - <label>File:</label> <input type="file" name="file" /><br /> - <input type="submit" value="upload" /> - </form> - '; - - $output .= ob_get_clean(); + $output .= <<<HTML +<form method="post" action=""> +<h3>Create new folder</h3> +<input type="hidden" name="sabreAction" value="mkcol" /> +<label>Name:</label> <input type="text" name="name" /><br /> +<input type="submit" value="create" /> +</form> +<form method="post" action="" enctype="multipart/form-data"> +<h3>Upload file</h3> +<input type="hidden" name="sabreAction" value="put" /> +<label>Name (optional):</label> <input type="text" name="name" /><br /> +<label>File:</label> <input type="file" name="file" /><br /> +<input type="submit" value="upload" /> +</form> +HTML; } @@ -543,8 +547,8 @@ HTML; * This method returns a local pathname to an asset. * * @param string $assetName - * @return string * @throws DAV\Exception\NotFound + * @return string */ protected function getLocalAssetPath($assetName) { @@ -575,9 +579,9 @@ HTML; // Rudimentary mime type detection $mime = 'application/octet-stream'; $map = [ - 'ico' => 'image/vnd.microsoft.icon', - 'png' => 'image/png', - 'css' => 'text/css', + 'ico' => 'image/vnd.microsoft.icon', + 'png' => 'image/png', + 'css' => 'text/css', ]; $ext = substr($assetName, strrpos($assetName, '.') + 1); @@ -623,7 +627,7 @@ HTML; * Maps a resource type to a human-readable string and icon. * * @param array $resourceTypes - * @param INode $node + * @param DAV\INode $node * @return array */ private function mapResourceType(array $resourceTypes, $node) { diff --git a/vendor/sabre/dav/lib/DAV/Browser/PropFindAll.php b/vendor/sabre/dav/lib/DAV/Browser/PropFindAll.php index 1ac439672..c14b7f2f9 100644 --- a/vendor/sabre/dav/lib/DAV/Browser/PropFindAll.php +++ b/vendor/sabre/dav/lib/DAV/Browser/PropFindAll.php @@ -28,7 +28,7 @@ class PropFindAll extends PropFind { /** * Handles a specific property. * - * This method checks wether the specified property was requested in this + * This method checks whether the specified property was requested in this * PROPFIND request, and if so, it will call the callback and use the * return value for it's value. * diff --git a/vendor/sabre/dav/lib/DAV/Client.php b/vendor/sabre/dav/lib/DAV/Client.php index 08d5d4702..175ad1bc4 100644 --- a/vendor/sabre/dav/lib/DAV/Client.php +++ b/vendor/sabre/dav/lib/DAV/Client.php @@ -231,7 +231,7 @@ class Client extends HTTP\Client { $response = $this->send($request); if ((int)$response->getStatus() >= 400) { - throw new \Sabre\HTTP\ClientHttpException($response); + throw new HTTP\ClientHttpException($response); } $result = $this->parseMultiStatus($response->getBodyAsString()); @@ -281,7 +281,7 @@ class Client extends HTTP\Client { $response = $this->send($request); if ($response->getStatus() >= 400) { - throw new \Sabre\HTTP\ClientHttpException($response); + throw new HTTP\ClientHttpException($response); } if ($response->getStatus() === 207) { @@ -303,7 +303,7 @@ class Client extends HTTP\Client { } if ($errorProperties) { - throw new \Sabre\HTTP\ClientException('PROPPATCH failed. The following properties errored: ' . implode(', ', $errorProperties)); + throw new HTTP\ClientException('PROPPATCH failed. The following properties errored: ' . implode(', ', $errorProperties)); } } return true; diff --git a/vendor/sabre/dav/lib/DAV/Collection.php b/vendor/sabre/dav/lib/DAV/Collection.php index a46bcc342..35c90b5af 100644 --- a/vendor/sabre/dav/lib/DAV/Collection.php +++ b/vendor/sabre/dav/lib/DAV/Collection.php @@ -68,7 +68,7 @@ abstract class Collection extends Node implements ICollection { * Data will either be supplied as a stream resource, or in certain cases * as a string. Keep in mind that you may have to support either. * - * After succesful creation of the file, you may choose to return the ETag + * After successful creation of the file, you may choose to return the ETag * of the new file here. * * The returned ETag must be surrounded by double-quotes (The quotes should diff --git a/vendor/sabre/dav/lib/DAV/CorePlugin.php b/vendor/sabre/dav/lib/DAV/CorePlugin.php index a1b052915..676cdd04a 100644 --- a/vendor/sabre/dav/lib/DAV/CorePlugin.php +++ b/vendor/sabre/dav/lib/DAV/CorePlugin.php @@ -165,7 +165,7 @@ class CorePlugin extends ServerPlugin { } else { $start = $nodeSize - $range[1]; - $end = $nodeSize - 1; + $end = $nodeSize - 1; if ($start < 0) $start = 0; @@ -194,7 +194,7 @@ class CorePlugin extends ServerPlugin { $response->setBody($body); } - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -224,7 +224,7 @@ class CorePlugin extends ServerPlugin { $response->setHeader('Content-Length', '0'); $response->setStatus(200); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -264,7 +264,7 @@ class CorePlugin extends ServerPlugin { $response->setHeader('X-Sabre-Real-Status', $e->getHTTPCode()); } - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -290,7 +290,7 @@ class CorePlugin extends ServerPlugin { $response->setStatus(204); $response->setHeader('Content-Length', '0'); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -333,7 +333,7 @@ class CorePlugin extends ServerPlugin { // The only two options for the depth of a propfind is 0 or 1 - as long as depth infinity is not enabled if (!$this->server->enablePropfindDepthInfinity && $depth != 0) $depth = 1; - $newProperties = $this->server->getPropertiesForPath($path, $propFindXml->properties, $depth); + $newProperties = $this->server->getPropertiesIteratorForPath($path, $propFindXml->properties, $depth); // This is a multi-status response $response->setStatus(207); @@ -355,7 +355,7 @@ class CorePlugin extends ServerPlugin { $data = $this->server->generateMultiStatus($newProperties, $minimal); $response->setBody($data); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -390,7 +390,7 @@ class CorePlugin extends ServerPlugin { if ($prefer['return'] === 'minimal') { // If return-minimal is specified, we only have to check if the - // request was succesful, and don't need to return the + // request was successful, and don't need to return the // multi-status. $ok = true; foreach ($result as $prop => $code) { @@ -427,7 +427,7 @@ class CorePlugin extends ServerPlugin { $this->server->generateMultiStatus([$multiStatus]) ); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -533,7 +533,7 @@ class CorePlugin extends ServerPlugin { } - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -602,7 +602,7 @@ class CorePlugin extends ServerPlugin { $response->setStatus(201); } - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -653,7 +653,7 @@ class CorePlugin extends ServerPlugin { $response->setHeader('Content-Length', '0'); $response->setStatus($moveInfo['destinationExists'] ? 204 : 201); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -688,7 +688,7 @@ class CorePlugin extends ServerPlugin { $response->setHeader('Content-Length', '0'); $response->setStatus($copyInfo['destinationExists'] ? 204 : 201); - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -722,7 +722,7 @@ class CorePlugin extends ServerPlugin { } - // Sending back false will interupt the event chain and tell the server + // Sending back false will interrupt the event chain and tell the server // we've handled this method. return false; @@ -740,7 +740,7 @@ class CorePlugin extends ServerPlugin { */ function propPatchProtectedPropertyCheck($path, PropPatch $propPatch) { - // Comparing the mutation list to the list of propetected properties. + // Comparing the mutation list to the list of protected properties. $mutations = $propPatch->getMutations(); $protected = array_intersect( diff --git a/vendor/sabre/dav/lib/DAV/Exception/InvalidResourceType.php b/vendor/sabre/dav/lib/DAV/Exception/InvalidResourceType.php index 505fe5c10..6324d9f3a 100644 --- a/vendor/sabre/dav/lib/DAV/Exception/InvalidResourceType.php +++ b/vendor/sabre/dav/lib/DAV/Exception/InvalidResourceType.php @@ -19,7 +19,7 @@ class InvalidResourceType extends Forbidden { /** * This method allows the exception to include additional information into the WebDAV error response * - * @param DAV\Server $server + * @param \Sabre\DAV\Server $server * @param \DOMElement $errorNode * @return void */ diff --git a/vendor/sabre/dav/lib/DAV/FS/Node.php b/vendor/sabre/dav/lib/DAV/FS/Node.php index 831c11911..424718f96 100644 --- a/vendor/sabre/dav/lib/DAV/FS/Node.php +++ b/vendor/sabre/dav/lib/DAV/FS/Node.php @@ -43,7 +43,7 @@ abstract class Node implements DAV\INode { */ function getName() { - list(, $name) = URLUtil::splitPath($this->path); + list(, $name) = URLUtil::splitPath($this->path); return $name; } diff --git a/vendor/sabre/dav/lib/DAV/File.php b/vendor/sabre/dav/lib/DAV/File.php index 675956b22..5161fbd51 100644 --- a/vendor/sabre/dav/lib/DAV/File.php +++ b/vendor/sabre/dav/lib/DAV/File.php @@ -19,7 +19,7 @@ abstract class File extends Node implements IFile { * * The data argument is a readable stream resource. * - * After a succesful put operation, you may choose to return an ETag. The + * After a successful put operation, you may choose to return an ETag. The * etag must always be surrounded by double-quotes. These quotes must * appear in the actual string you're returning. * diff --git a/vendor/sabre/dav/lib/DAV/IFile.php b/vendor/sabre/dav/lib/DAV/IFile.php index 37e7cd33c..19d8d8637 100644 --- a/vendor/sabre/dav/lib/DAV/IFile.php +++ b/vendor/sabre/dav/lib/DAV/IFile.php @@ -20,7 +20,7 @@ interface IFile extends INode { * * The data argument is a readable stream resource. * - * After a succesful put operation, you may choose to return an ETag. The + * After a successful put operation, you may choose to return an ETag. The * etag must always be surrounded by double-quotes. These quotes must * appear in the actual string you're returning. * @@ -32,7 +32,7 @@ interface IFile extends INode { * different object on a subsequent GET you are strongly recommended to not * return an ETag, and just return null. * - * @param resource|data $data + * @param resource|string $data * @return string|null */ function put($data); diff --git a/vendor/sabre/dav/lib/DAV/IMoveTarget.php b/vendor/sabre/dav/lib/DAV/IMoveTarget.php index f0f67bc26..92fde1d5c 100644 --- a/vendor/sabre/dav/lib/DAV/IMoveTarget.php +++ b/vendor/sabre/dav/lib/DAV/IMoveTarget.php @@ -7,7 +7,7 @@ namespace Sabre\DAV; * nodes may be moved into this collection". * * The benefit of this, is that sabre/dav will by default perform a move, by - * tranfersing an entire directory tree, copying every collection, and deleting + * transferring an entire directory tree, copying every collection, and deleting * every item. * * If a backend supports a better optimized move operation, this can trigger diff --git a/vendor/sabre/dav/lib/DAV/Locks/Backend/PDO.php b/vendor/sabre/dav/lib/DAV/Locks/Backend/PDO.php index a01d9bae4..510f266f7 100644 --- a/vendor/sabre/dav/lib/DAV/Locks/Backend/PDO.php +++ b/vendor/sabre/dav/lib/DAV/Locks/Backend/PDO.php @@ -33,7 +33,7 @@ class PDO extends AbstractBackend { /** * Constructor * - * @param PDO $pdo + * @param \PDO $pdo */ function __construct(\PDO $pdo) { @@ -102,7 +102,7 @@ class PDO extends AbstractBackend { $lockInfo->created = $row['created']; $lockInfo->scope = $row['scope']; $lockInfo->depth = $row['depth']; - $lockInfo->uri = $row['uri']; + $lockInfo->uri = $row['uri']; $lockList[] = $lockInfo; } diff --git a/vendor/sabre/dav/lib/DAV/Locks/Plugin.php b/vendor/sabre/dav/lib/DAV/Locks/Plugin.php index 4855b7076..41a3bf3fa 100644 --- a/vendor/sabre/dav/lib/DAV/Locks/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Locks/Plugin.php @@ -25,14 +25,14 @@ class Plugin extends DAV\ServerPlugin { /** * locksBackend * - * @var Backend\Backend\Interface + * @var Backend\BackendInterface */ protected $locksBackend; /** * server * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; @@ -256,7 +256,7 @@ class Plugin extends DAV\ServerPlugin { $response->setStatus($newFile ? 201 : 200); $response->setBody($this->generateLockResponse($lockInfo)); - // Returning false will interupt the event chain and mark this method + // Returning false will interrupt the event chain and mark this method // as 'handled'. return false; diff --git a/vendor/sabre/dav/lib/DAV/MkCol.php b/vendor/sabre/dav/lib/DAV/MkCol.php index c79055418..042e14bca 100644 --- a/vendor/sabre/dav/lib/DAV/MkCol.php +++ b/vendor/sabre/dav/lib/DAV/MkCol.php @@ -61,6 +61,7 @@ class MkCol extends PropPatch { * checked. * * @param string|string[] $resourceType + * @return bool */ function hasResourceType($resourceType) { diff --git a/vendor/sabre/dav/lib/DAV/Mount/Plugin.php b/vendor/sabre/dav/lib/DAV/Mount/Plugin.php index 8e06acb9f..dc923ad85 100644 --- a/vendor/sabre/dav/lib/DAV/Mount/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Mount/Plugin.php @@ -20,7 +20,7 @@ class Plugin extends DAV\ServerPlugin { /** * Reference to Server class * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/lib/DAV/Node.php b/vendor/sabre/dav/lib/DAV/Node.php index ba270e8f9..ef6eea18e 100644 --- a/vendor/sabre/dav/lib/DAV/Node.php +++ b/vendor/sabre/dav/lib/DAV/Node.php @@ -29,7 +29,7 @@ abstract class Node implements INode { /** * Deletes the current node * - * @throws Sabre\DAV\Exception\Forbidden + * @throws Exception\Forbidden * @return void */ function delete() { @@ -41,8 +41,8 @@ abstract class Node implements INode { /** * Renames the node * - * @throws Sabre\DAV\Exception\Forbidden * @param string $name The new name + * @throws Exception\Forbidden * @return void */ function setName($name) { diff --git a/vendor/sabre/dav/lib/DAV/PartialUpdate/Plugin.php b/vendor/sabre/dav/lib/DAV/PartialUpdate/Plugin.php index 24ba970b1..9c129d705 100644 --- a/vendor/sabre/dav/lib/DAV/PartialUpdate/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/PartialUpdate/Plugin.php @@ -29,7 +29,7 @@ class Plugin extends DAV\ServerPlugin { /** * Reference to server * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/lib/DAV/PropFind.php b/vendor/sabre/dav/lib/DAV/PropFind.php index 8ae6b6cfd..0940a1ce2 100644 --- a/vendor/sabre/dav/lib/DAV/PropFind.php +++ b/vendor/sabre/dav/lib/DAV/PropFind.php @@ -72,7 +72,7 @@ class PropFind { /** * Handles a specific property. * - * This method checks wether the specified property was requested in this + * This method checks whether the specified property was requested in this * PROPFIND request, and if so, it will call the callback and use the * return value for it's value. * diff --git a/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php b/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php index 31ecafdb2..b15d7fef9 100644 --- a/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php +++ b/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php @@ -23,7 +23,7 @@ interface BackendInterface { * This method received a PropFind object, which contains all the * information about the properties that need to be fetched. * - * Ususually you would just want to call 'get404Properties' on this object, + * Usually you would just want to call 'get404Properties' on this object, * as this will give you the _exact_ list of properties that need to be * fetched, and haven't yet. * diff --git a/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php b/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php index 2fe843884..6f3f1feaf 100644 --- a/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php +++ b/vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php @@ -66,7 +66,7 @@ class PDO implements BackendInterface { * This method received a PropFind object, which contains all the * information about the properties that need to be fetched. * - * Ususually you would just want to call 'get404Properties' on this object, + * Usually you would just want to call 'get404Properties' on this object, * as this will give you the _exact_ list of properties that need to be * fetched, and haven't yet. * diff --git a/vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php b/vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php index 0c28b7882..a66a14113 100644 --- a/vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php @@ -2,11 +2,11 @@ namespace Sabre\DAV\PropertyStorage; +use Sabre\DAV\INode; +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; -use Sabre\DAV\PropPatch; -use Sabre\DAV\PropFind; -use Sabre\DAV\INode; /** * PropertyStorage Plugin. @@ -30,7 +30,7 @@ class Plugin extends ServerPlugin { * paths, you can use a pathFilter to do this. * * The pathFilter should be a callable. The callable retrieves a path as - * its argument, and should return true or false wether it allows + * its argument, and should return true or false whether it allows * properties to be stored. * * @var callable @@ -38,6 +38,11 @@ class Plugin extends ServerPlugin { public $pathFilter; /** + * @var Backend\BackendInterface + */ + public $backend; + + /** * Creates the plugin * * @param Backend\BackendInterface $backend diff --git a/vendor/sabre/dav/lib/DAV/Server.php b/vendor/sabre/dav/lib/DAV/Server.php index 024b7a557..6805ec0b0 100644 --- a/vendor/sabre/dav/lib/DAV/Server.php +++ b/vendor/sabre/dav/lib/DAV/Server.php @@ -2,16 +2,16 @@ namespace Sabre\DAV; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Sabre\Event\EventEmitter; use Sabre\HTTP; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; use Sabre\HTTP\URLUtil; use Sabre\Uri; -use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerAwareTrait; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; /** * Main DAV server class @@ -37,7 +37,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { /** * The tree object * - * @var Sabre\DAV\Tree + * @var Tree */ public $tree; @@ -51,21 +51,21 @@ class Server extends EventEmitter implements LoggerAwareInterface { /** * httpResponse * - * @var Sabre\HTTP\Response + * @var HTTP\Response */ public $httpResponse; /** * httpRequest * - * @var Sabre\HTTP\Request + * @var HTTP\Request */ public $httpRequest; /** * PHP HTTP Sapi * - * @var Sabre\HTTP\Sapi + * @var HTTP\Sapi */ public $sapi; @@ -437,7 +437,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { } /** - * Returns the PSR-3 logger objcet. + * Returns the PSR-3 logger object. * * @return LoggerInterface */ @@ -455,7 +455,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { * * @param RequestInterface $request * @param ResponseInterface $response - * @param $sendResponse Whether to send the HTTP response to the DAV client. + * @param bool $sendResponse Whether to send the HTTP response to the DAV client. * @return void */ function invokeMethod(RequestInterface $request, ResponseInterface $response, $sendResponse = true) { @@ -681,18 +681,18 @@ class Server extends EventEmitter implements LoggerAwareInterface { // can be true or false 'respond-async' => false, // Could be set to 'representation' or 'minimal'. - 'return' => null, + 'return' => null, // Used as a timeout, is usually a number. - 'wait' => null, + 'wait' => null, // can be 'strict' or 'lenient'. - 'handling' => false, + 'handling' => false, ]; if ($prefer = $this->httpRequest->getHeader('Prefer')) { $result = array_merge( $result, - \Sabre\HTTP\parsePrefer($prefer) + HTTP\parsePrefer($prefer) ); } elseif ($this->httpRequest->getHeader('Brief') == 't') { @@ -794,6 +794,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { * * @param string $path * @param array $propertyNames + * @return array */ function getProperties($path, $propertyNames) { @@ -877,12 +878,14 @@ class Server extends EventEmitter implements LoggerAwareInterface { /** * Small helper to support PROPFIND with DEPTH_INFINITY. * - * @param array[] $propFindRequests * @param PropFind $propFind - * @return void + * @param array $yieldFirst + * @return \Iterator */ - private function addPathNodesRecursively(&$propFindRequests, PropFind $propFind) { - + private function generatePathNodes(PropFind $propFind, array $yieldFirst = null) { + if ($yieldFirst !== null) { + yield $yieldFirst; + } $newDepth = $propFind->getDepth(); $path = $propFind->getPath(); @@ -900,13 +903,15 @@ class Server extends EventEmitter implements LoggerAwareInterface { } $subPropFind->setPath($subPath); - $propFindRequests[] = [ + yield [ $subPropFind, $childNode ]; if (($newDepth === self::DEPTH_INFINITY || $newDepth >= 1) && $childNode instanceof ICollection) { - $this->addPathNodesRecursively($propFindRequests, $subPropFind); + foreach ($this->generatePathNodes($subPropFind) as $subItem) { + yield $subItem; + } } } @@ -925,9 +930,31 @@ class Server extends EventEmitter implements LoggerAwareInterface { * @param array $propertyNames * @param int $depth * @return array + * + * @deprecated Use getPropertiesIteratorForPath() instead (as it's more memory efficient) + * @see getPropertiesIteratorForPath() */ function getPropertiesForPath($path, $propertyNames = [], $depth = 0) { + return iterator_to_array($this->getPropertiesIteratorForPath($path, $propertyNames, $depth)); + + } + /** + * Returns a list of properties for a given path + * + * The path that should be supplied should have the baseUrl stripped out + * The list of properties should be supplied in Clark notation. If the list is empty + * 'allprops' is assumed. + * + * If a depth of 1 is requested child elements will also be returned. + * + * @param string $path + * @param array $propertyNames + * @param int $depth + * @return \Iterator + */ + function getPropertiesIteratorForPath($path, $propertyNames = [], $depth = 0) { + // The only two options for the depth of a propfind is 0 or 1 - as long as depth infinity is not enabled if (!$this->enablePropfindDepthInfinity && $depth != 0) $depth = 1; @@ -944,11 +971,9 @@ class Server extends EventEmitter implements LoggerAwareInterface { ]]; if (($depth > 0 || $depth === self::DEPTH_INFINITY) && $parentNode instanceof ICollection) { - $this->addPathNodesRecursively($propFindRequests, $propFind); + $propFindRequests = $this->generatePathNodes(clone $propFind, current($propFindRequests)); } - $returnPropertyList = []; - foreach ($propFindRequests as $propFindRequest) { list($propFind, $node) = $propFindRequest; @@ -965,13 +990,11 @@ class Server extends EventEmitter implements LoggerAwareInterface { if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) { $result['href'] .= '/'; } - $returnPropertyList[] = $result; + yield $result; } } - return $returnPropertyList; - } /** @@ -1430,7 +1453,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { // Plugins are responsible for validating all the tokens. // If a plugin deemed a token 'valid', it will set 'validToken' to // true. - $this->emit('validateTokens', [ $request, &$ifConditions ]); + $this->emit('validateTokens', [$request, &$ifConditions]); // Now we're going to analyze the result. @@ -1450,7 +1473,7 @@ class Server extends EventEmitter implements LoggerAwareInterface { if (!$token['etag']) { $etagValid = true; } - // Checking the ETag, only if the token was already deamed + // Checking the ETag, only if the token was already deemed // valid and there is one. if ($token['etag'] && $tokenValid) { @@ -1626,13 +1649,18 @@ class Server extends EventEmitter implements LoggerAwareInterface { * * If 'strip404s' is set to true, all 404 responses will be removed. * - * @param array $fileProperties The list with nodes - * @param bool strip404s + * @param array|\Traversable $fileProperties The list with nodes + * @param bool $strip404s * @return string */ - function generateMultiStatus(array $fileProperties, $strip404s = false) { + function generateMultiStatus($fileProperties, $strip404s = false) { - $xml = []; + $w = $this->xml->getWriter(); + $w->openMemory(); + $w->contextUri = $this->baseUri; + $w->startDocument(); + + $w->startElement('{DAV:}multistatus'); foreach ($fileProperties as $entry) { @@ -1645,13 +1673,14 @@ class Server extends EventEmitter implements LoggerAwareInterface { ltrim($href, '/'), $entry ); - $xml[] = [ + $w->write([ 'name' => '{DAV:}response', 'value' => $response - ]; - + ]); } - return $this->xml->write('{DAV:}multistatus', $xml, $this->baseUri); + $w->endElement(); + + return $w->outputMemory(); } diff --git a/vendor/sabre/dav/lib/DAV/Sharing/Plugin.php b/vendor/sabre/dav/lib/DAV/Sharing/Plugin.php index 354d06a56..ef5702c57 100644 --- a/vendor/sabre/dav/lib/DAV/Sharing/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Sharing/Plugin.php @@ -8,8 +8,8 @@ use Sabre\DAV\INode; use Sabre\DAV\PropFind; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; -use Sabre\DAV\Xml\Property; use Sabre\DAV\Xml\Element\Sharee; +use Sabre\DAV\Xml\Property; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -40,7 +40,7 @@ class Plugin extends ServerPlugin { /** * Reference to SabreDAV server object. * - * @var Sabre\DAV\Server + * @var Server */ protected $server; diff --git a/vendor/sabre/dav/lib/DAV/Sync/Plugin.php b/vendor/sabre/dav/lib/DAV/Sync/Plugin.php index 4a141c72b..8e4b1aa64 100644 --- a/vendor/sabre/dav/lib/DAV/Sync/Plugin.php +++ b/vendor/sabre/dav/lib/DAV/Sync/Plugin.php @@ -3,8 +3,8 @@ namespace Sabre\DAV\Sync; use Sabre\DAV; -use Sabre\HTTP\RequestInterface; use Sabre\DAV\Xml\Request\SyncCollectionReport; +use Sabre\HTTP\RequestInterface; /** * This plugin all WebDAV-sync capabilities to the Server. diff --git a/vendor/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php b/vendor/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php index c5b8aa1ca..7b453d105 100644 --- a/vendor/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php +++ b/vendor/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php @@ -14,7 +14,7 @@ use Sabre\HTTP\URLUtil; * a WebDAV share as a disk. * * It will intercept these files and place them in a separate directory. - * these files are not deleted automatically, so it is adviceable to + * these files are not deleted automatically, so it is advisable to * delete these after they are not accessed for 24 hours. * * Currently it supports: @@ -51,7 +51,7 @@ class TemporaryFileFilterPlugin extends ServerPlugin { /** * A reference to the main Server class * - * @var Sabre\DAV\Server + * @var \Sabre\DAV\Server */ protected $server; @@ -134,12 +134,12 @@ class TemporaryFileFilterPlugin extends ServerPlugin { * * @param string $uri * @param resource $data - * @param DAV\ICollection $parentNode + * @param ICollection $parent * @param bool $modified Should be set to true, if this event handler * changed &$data. * @return bool */ - function beforeCreateFile($uri, $data, $parent, $modified) { + function beforeCreateFile($uri, $data, ICollection $parent, $modified) { if ($tempPath = $this->isTempFile($uri)) { diff --git a/vendor/sabre/dav/lib/DAV/Version.php b/vendor/sabre/dav/lib/DAV/Version.php index 2fda85db8..89918e5bc 100644 --- a/vendor/sabre/dav/lib/DAV/Version.php +++ b/vendor/sabre/dav/lib/DAV/Version.php @@ -14,6 +14,6 @@ class Version { /** * Full version number */ - const VERSION = '3.2.0'; + const VERSION = '3.2.2'; } diff --git a/vendor/sabre/dav/lib/DAV/Xml/Element/Prop.php b/vendor/sabre/dav/lib/DAV/Xml/Element/Prop.php index db5332c50..71ef03e3f 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Element/Prop.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Element/Prop.php @@ -3,8 +3,8 @@ namespace Sabre\DAV\Xml\Element; use Sabre\DAV\Xml\Property\Complex; -use Sabre\Xml\XmlDeserializable; use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * This class is responsible for decoding the {DAV:}prop element as it appears @@ -22,7 +22,7 @@ class Prop implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -90,7 +90,7 @@ class Prop implements XmlDeserializable { if (array_key_exists($name, $reader->elementMap)) { $deserializer = $reader->elementMap[$name]; if (is_subclass_of($deserializer, 'Sabre\\Xml\\XmlDeserializable')) { - $value = call_user_func([ $deserializer, 'xmlDeserialize' ], $reader); + $value = call_user_func([$deserializer, 'xmlDeserialize'], $reader); } elseif (is_callable($deserializer)) { $value = call_user_func($deserializer, $reader); } else { diff --git a/vendor/sabre/dav/lib/DAV/Xml/Element/Response.php b/vendor/sabre/dav/lib/DAV/Xml/Element/Response.php index 97a2bb59f..ce97ae943 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Element/Response.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Element/Response.php @@ -160,7 +160,7 @@ class Response implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Element/Sharee.php b/vendor/sabre/dav/lib/DAV/Xml/Element/Sharee.php index dcfd7bd2e..e187bf11c 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Element/Sharee.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Element/Sharee.php @@ -105,7 +105,7 @@ class Sharee implements Element { * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -146,7 +146,7 @@ class Sharee implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/Complex.php b/vendor/sabre/dav/lib/DAV/Xml/Property/Complex.php index 1d9202082..258806e4a 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/Complex.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/Complex.php @@ -20,7 +20,7 @@ class Complex extends XmlFragment { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/GetLastModified.php b/vendor/sabre/dav/lib/DAV/Xml/Property/GetLastModified.php index 2db47269f..101a0f0c9 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/GetLastModified.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/GetLastModified.php @@ -2,12 +2,12 @@ namespace Sabre\DAV\Xml\Property; +use DateTime; +use DateTimeZone; +use Sabre\HTTP; use Sabre\Xml\Element; use Sabre\Xml\Reader; use Sabre\Xml\Writer; -use Sabre\HTTP; -use DateTime; -use DateTimeZone; /** * This property represents the {DAV:}getlastmodified property. @@ -83,7 +83,7 @@ class GetLastModified implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/Href.php b/vendor/sabre/dav/lib/DAV/Xml/Property/Href.php index 0027f72e1..6c4f11b87 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/Href.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/Href.php @@ -4,10 +4,10 @@ namespace Sabre\DAV\Xml\Property; use Sabre\DAV\Browser\HtmlOutput; use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\Uri; use Sabre\Xml\Element; use Sabre\Xml\Reader; use Sabre\Xml\Writer; -use Sabre\Uri; /** * Href property @@ -40,7 +40,7 @@ class Href implements Element, HtmlOutput { * If auto-prefix is set to false, the hrefs will be treated as absolute * and not relative to the servers base uri. * - * @param string|string[] $href + * @param string|string[] $hrefs */ function __construct($hrefs) { @@ -74,12 +74,12 @@ class Href implements Element, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -128,7 +128,7 @@ class Href implements Element, HtmlOutput { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/Invite.php b/vendor/sabre/dav/lib/DAV/Xml/Property/Invite.php index 0616ff113..6adad3650 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/Invite.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/Invite.php @@ -2,9 +2,9 @@ namespace Sabre\DAV\Xml\Property; -use Sabre\DAV\Sharing\Sharee; -use Sabre\Xml\XmlSerializable; +use Sabre\DAV\Xml\Element\Sharee; use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * This class represents the {DAV:}invite property. @@ -46,7 +46,7 @@ class Invite implements XmlSerializable { * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/LocalHref.php b/vendor/sabre/dav/lib/DAV/Xml/Property/LocalHref.php index 76a27b95d..00d2fa708 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/LocalHref.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/LocalHref.php @@ -8,7 +8,7 @@ use Sabre\HTTP; * LocalHref property * * Like the Href property, this element represents {DAV:}href. The difference - * is that this is used stricly for paths on the server. The LocalHref property + * is that this is used strictly for paths on the server. The LocalHref property * will prepare the path so it's a valid URI. * * These two objects behave identically: @@ -32,7 +32,7 @@ class LocalHref extends Href { * If auto-prefix is set to false, the hrefs will be treated as absolute * and not relative to the servers base uri. * - * @param string|string[] $href + * @param string|string[] $hrefs */ function __construct($hrefs) { diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/ResourceType.php b/vendor/sabre/dav/lib/DAV/Xml/Property/ResourceType.php index 302888321..ce640ff32 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/ResourceType.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/ResourceType.php @@ -28,7 +28,7 @@ class ResourceType extends Element\Elements implements HtmlOutput { * * The resourcetype must be specified in clark-notation * - * @param array|string|null $resourceType + * @param array|string|null $resourceTypes */ function __construct($resourceTypes = null) { @@ -77,7 +77,7 @@ class ResourceType extends Element\Elements implements HtmlOutput { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/ShareAccess.php b/vendor/sabre/dav/lib/DAV/Xml/Property/ShareAccess.php index a3fc6b0e1..939062f76 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/ShareAccess.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/ShareAccess.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Xml\Property; -use Sabre\DAV\Sharing\Plugin as SharingPlugin; use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Sharing\Plugin as SharingPlugin; use Sabre\Xml\Element; use Sabre\Xml\Reader; use Sabre\Xml\Writer; @@ -62,7 +62,7 @@ class ShareAccess implements Element { * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -102,7 +102,7 @@ class ShareAccess implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedLock.php b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedLock.php index f6d01aa37..677fdde4b 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedLock.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedLock.php @@ -21,12 +21,12 @@ use Sabre\Xml\XmlSerializable; class SupportedLock implements XmlSerializable { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -43,11 +43,11 @@ class SupportedLock implements XmlSerializable { $writer->writeElement('{DAV:}lockentry', [ '{DAV:}lockscope' => ['{DAV:}exclusive' => null], - '{DAV:}locktype' => ['{DAV:}write' => null], + '{DAV:}locktype' => ['{DAV:}write' => null], ]); $writer->writeElement('{DAV:}lockentry', [ '{DAV:}lockscope' => ['{DAV:}shared' => null], - '{DAV:}locktype' => ['{DAV:}write' => null], + '{DAV:}locktype' => ['{DAV:}write' => null], ]); } diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedMethodSet.php b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedMethodSet.php index 7641f3739..1a3878ef7 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedMethodSet.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedMethodSet.php @@ -67,12 +67,12 @@ class SupportedMethodSet implements XmlSerializable, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedReportSet.php b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedReportSet.php index ebf27300d..96383ec96 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedReportSet.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Property/SupportedReportSet.php @@ -98,12 +98,12 @@ class SupportedReportSet implements XmlSerializable, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/Lock.php b/vendor/sabre/dav/lib/DAV/Xml/Request/Lock.php index 76df98d13..c315a9a45 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/Lock.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/Lock.php @@ -38,7 +38,7 @@ class Lock implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/MkCol.php b/vendor/sabre/dav/lib/DAV/Xml/Request/MkCol.php index 5db239061..9490bf58c 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/MkCol.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/MkCol.php @@ -40,7 +40,7 @@ class MkCol implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -63,8 +63,8 @@ class MkCol implements XmlDeserializable { $self = new self(); $elementMap = $reader->elementMap; - $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; - $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; + $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; + $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; $elementMap['{DAV:}remove'] = 'Sabre\Xml\Element\KeyValue'; $elems = $reader->parseInnerTree($elementMap); diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/PropFind.php b/vendor/sabre/dav/lib/DAV/Xml/Request/PropFind.php index ad3ad7c43..f1b5b6fdc 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/PropFind.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/PropFind.php @@ -36,7 +36,7 @@ class PropFind implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/PropPatch.php b/vendor/sabre/dav/lib/DAV/Xml/Request/PropPatch.php index 07a05f887..821b9e047 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/PropPatch.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/PropPatch.php @@ -29,12 +29,12 @@ class PropPatch implements Element { public $properties = []; /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -68,7 +68,7 @@ class PropPatch implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -91,8 +91,8 @@ class PropPatch implements Element { $self = new self(); $elementMap = $reader->elementMap; - $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; - $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; + $elementMap['{DAV:}prop'] = 'Sabre\DAV\Xml\Element\Prop'; + $elementMap['{DAV:}set'] = 'Sabre\Xml\Element\KeyValue'; $elementMap['{DAV:}remove'] = 'Sabre\Xml\Element\KeyValue'; $elems = $reader->parseInnerTree($elementMap); diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/ShareResource.php b/vendor/sabre/dav/lib/DAV/Xml/Request/ShareResource.php index 965e5857c..526a4eb6f 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/ShareResource.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/ShareResource.php @@ -2,9 +2,9 @@ namespace Sabre\DAV\Xml\Request; +use Sabre\DAV\Xml\Element\Sharee; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Xml\Element\Sharee; /** * ShareResource request parser. @@ -40,7 +40,7 @@ class ShareResource implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAV/Xml/Request/SyncCollectionReport.php b/vendor/sabre/dav/lib/DAV/Xml/Request/SyncCollectionReport.php index 3092ada47..830293a01 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Request/SyncCollectionReport.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Request/SyncCollectionReport.php @@ -2,10 +2,10 @@ namespace Sabre\DAV\Xml\Request; +use Sabre\DAV\Exception\BadRequest; +use Sabre\Xml\Element\KeyValue; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Element\KeyValue; -use Sabre\DAV\Exception\BadRequest; /** * SyncCollection request parser. @@ -51,7 +51,7 @@ class SyncCollectionReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are @@ -75,7 +75,7 @@ class SyncCollectionReport implements XmlDeserializable { $reader->pushContext(); - $reader->elementMap['{DAV:}prop'] = 'Sabre\Xml\Element\Elements'; + $reader->elementMap['{DAV:}prop'] = 'Sabre\Xml\Element\Elements'; $elems = KeyValue::xmlDeserialize($reader); $reader->popContext(); diff --git a/vendor/sabre/dav/lib/DAV/Xml/Response/MultiStatus.php b/vendor/sabre/dav/lib/DAV/Xml/Response/MultiStatus.php index 16a3d4a68..cf5a0453b 100644 --- a/vendor/sabre/dav/lib/DAV/Xml/Response/MultiStatus.php +++ b/vendor/sabre/dav/lib/DAV/Xml/Response/MultiStatus.php @@ -99,7 +99,7 @@ class MultiStatus implements Element { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Exception/NotRecognizedPrincipal.php b/vendor/sabre/dav/lib/DAVACL/Exception/NotRecognizedPrincipal.php index 4349bf101..d7ae188ae 100644 --- a/vendor/sabre/dav/lib/DAVACL/Exception/NotRecognizedPrincipal.php +++ b/vendor/sabre/dav/lib/DAVACL/Exception/NotRecognizedPrincipal.php @@ -5,7 +5,7 @@ namespace Sabre\DAVACL\Exception; use Sabre\DAV; /** - * If a client tried to set a privilege assigned to a non-existant principal, + * If a client tried to set a privilege assigned to a non-existent principal, * this exception will be thrown. * * @copyright Copyright (C) fruux GmbH (https://fruux.com/) diff --git a/vendor/sabre/dav/lib/DAVACL/FS/Collection.php b/vendor/sabre/dav/lib/DAVACL/FS/Collection.php index 1c08b43b1..b4fe7a1b0 100644 --- a/vendor/sabre/dav/lib/DAVACL/FS/Collection.php +++ b/vendor/sabre/dav/lib/DAVACL/FS/Collection.php @@ -2,11 +2,11 @@ namespace Sabre\DAVACL\FS; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; use Sabre\DAV\FSExt\Directory as BaseCollection; use Sabre\DAVACL\ACLTrait; use Sabre\DAVACL\IACL; -use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotFound; /** * This is an ACL-enabled collection. diff --git a/vendor/sabre/dav/lib/DAVACL/FS/File.php b/vendor/sabre/dav/lib/DAVACL/FS/File.php index 387597bf7..aaf2ae148 100644 --- a/vendor/sabre/dav/lib/DAVACL/FS/File.php +++ b/vendor/sabre/dav/lib/DAVACL/FS/File.php @@ -3,8 +3,8 @@ namespace Sabre\DAVACL\FS; use Sabre\DAV\FSExt\File as BaseFile; -use Sabre\DAVACL\IACL; use Sabre\DAVACL\ACLTrait; +use Sabre\DAVACL\IACL; /** * This is an ACL-enabled file node. diff --git a/vendor/sabre/dav/lib/DAVACL/FS/HomeCollection.php b/vendor/sabre/dav/lib/DAVACL/FS/HomeCollection.php index 9e21353ea..201235e5a 100644 --- a/vendor/sabre/dav/lib/DAVACL/FS/HomeCollection.php +++ b/vendor/sabre/dav/lib/DAVACL/FS/HomeCollection.php @@ -72,7 +72,7 @@ class HomeCollection extends AbstractPrincipalCollection implements IACL { * supplied by the authentication backend. * * @param array $principalInfo - * @return \Sabre\DAVACL\INode + * @return \Sabre\DAV\INode */ function getChildForPrincipal(array $principalInfo) { diff --git a/vendor/sabre/dav/lib/DAVACL/Plugin.php b/vendor/sabre/dav/lib/DAVACL/Plugin.php index 8e912309e..a2aa118d7 100644 --- a/vendor/sabre/dav/lib/DAVACL/Plugin.php +++ b/vendor/sabre/dav/lib/DAVACL/Plugin.php @@ -3,11 +3,12 @@ namespace Sabre\DAVACL; use Sabre\DAV; -use Sabre\DAV\INode; -use Sabre\DAV\Xml\Property\Href; use Sabre\DAV\Exception\BadRequest; -use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotAuthenticated; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\INode; +use Sabre\DAV\Xml\Property\Href; use Sabre\DAVACL\Exception\NeedPrivileges; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -53,7 +54,7 @@ class Plugin extends DAV\ServerPlugin { /** * Reference to server object. * - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; @@ -228,14 +229,14 @@ class Plugin extends DAV\ServerPlugin { /** * Returns the standard users' principal. * - * This is one authorative principal url for the current user. + * This is one authoritative principal url for the current user. * This method will return null if the user wasn't logged in. * * @return string|null */ function getCurrentUserPrincipal() { - /** @var $authPlugin Sabre\DAV\Auth\Plugin */ + /** @var $authPlugin \Sabre\DAV\Auth\Plugin */ $authPlugin = $this->server->getPlugin('auth'); if (!$authPlugin) { return null; @@ -283,8 +284,7 @@ class Plugin extends DAV\ServerPlugin { * * These rules are used for all nodes that don't implement the IACL interface. * - * @param array $acl - * @return void + * @return array */ function getDefaultAcl() { @@ -299,7 +299,7 @@ class Plugin extends DAV\ServerPlugin { * set of rules allow anyone to do anything, as long as they are * authenticated. * - * var array + * @var array */ protected $defaultAcl = [ [ @@ -321,7 +321,7 @@ class Plugin extends DAV\ServerPlugin { /** * Returns all the principal groups the specified principal is a member of. * - * @param string $principal + * @param string $mainPrincipal * @return array */ function getPrincipalMembership($mainPrincipal) { @@ -365,7 +365,7 @@ class Plugin extends DAV\ServerPlugin { /** * Find out of a principal equals another principal. * - * This is a quick way to find out wether a principal URI is part of a + * This is a quick way to find out whether a principal URI is part of a * group, or any subgroups. * * The first argument is the principal URI you want to check against. For @@ -373,10 +373,10 @@ class Plugin extends DAV\ServerPlugin { * which you want to find out of it is the same as the first principal, or * in a member of the first principal's group or subgroups. * - * So the arguments are not interchangable. If principal A is in group B, + * So the arguments are not interchangeable. If principal A is in group B, * passing 'B', 'A' will yield true, but 'A', 'B' is false. * - * If the sceond argument is not passed, we will use the current user + * If the second argument is not passed, we will use the current user * principal. * * @param string $checkPrincipal @@ -412,8 +412,8 @@ class Plugin extends DAV\ServerPlugin { * ] * ] * - * Privileges can be nested using "aggregrates". Doing so means that - * if you assign someone the aggregrating privilege, all the + * Privileges can be nested using "aggregates". Doing so means that + * if you assign someone the aggregating privilege, all the * sub-privileges will automatically be granted. * * Marking a privilege as abstract means that the privilege cannot be @@ -484,7 +484,7 @@ class Plugin extends DAV\ServerPlugin { ], ], ]; - if ($node instanceof \Sabre\DAV\ICollection) { + if ($node instanceof DAV\ICollection) { $supportedPrivileges['{DAV:}write']['aggregates']['{DAV:}bind'] = [ 'abstract' => false, 'aggregates' => [], @@ -494,7 +494,7 @@ class Plugin extends DAV\ServerPlugin { 'aggregates' => [], ]; } - if ($node instanceof \Sabre\DAVACL\IACL) { + if ($node instanceof IACL) { $supportedPrivileges['{DAV:}write']['aggregates']['{DAV:}write-acl'] = [ 'abstract' => false, 'aggregates' => [], @@ -980,8 +980,6 @@ class Plugin extends DAV\ServerPlugin { * * @param DAV\PropFind $propFind * @param DAV\INode $node - * @param array $requestedProperties - * @param array $returnedProperties * @TODO really should be broken into multiple methods, or even a class. * @return bool */ @@ -1423,7 +1421,7 @@ class Plugin extends DAV\ServerPlugin { ]; } - // Replacing the property with its expannded form. + // Replacing the property with its expanded form. $node[200][$propertyName] = $childProps; } diff --git a/vendor/sabre/dav/lib/DAVACL/Principal.php b/vendor/sabre/dav/lib/DAVACL/Principal.php index 6ebb30907..d7db94999 100644 --- a/vendor/sabre/dav/lib/DAVACL/Principal.php +++ b/vendor/sabre/dav/lib/DAVACL/Principal.php @@ -41,7 +41,7 @@ class Principal extends DAV\Node implements IPrincipal, DAV\IProperties, IACL { /** * Creates the principal object * - * @param IPrincipalBackend $principalBackend + * @param PrincipalBackend\BackendInterface $principalBackend * @param array $principalProperties */ function __construct(PrincipalBackend\BackendInterface $principalBackend, array $principalProperties = []) { diff --git a/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/BackendInterface.php b/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/BackendInterface.php index 2cb83071a..40b6e33ea 100644 --- a/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/BackendInterface.php +++ b/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/BackendInterface.php @@ -53,7 +53,7 @@ interface BackendInterface { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $path * @param \Sabre\DAV\PropPatch $propPatch diff --git a/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/PDO.php b/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/PDO.php index a491dc88f..eb0df888b 100644 --- a/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/PDO.php +++ b/vendor/sabre/dav/lib/DAVACL/PrincipalBackend/PDO.php @@ -11,7 +11,7 @@ use Sabre\HTTP\URLUtil; * * * This backend assumes all principals are in a single collection. The default collection - * is 'principals/', but this can be overriden. + * is 'principals/', but this can be overridden. * * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) @@ -65,7 +65,7 @@ class PDO extends AbstractBackend implements CreatePrincipalSupport { /** * Sets up the backend. * - * @param PDO $pdo + * @param \PDO $pdo */ function __construct(\PDO $pdo) { @@ -171,7 +171,7 @@ class PDO extends AbstractBackend implements CreatePrincipalSupport { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $path * @param DAV\PropPatch $propPatch @@ -307,7 +307,7 @@ class PDO extends AbstractBackend implements CreatePrincipalSupport { case "mailto": $query = 'SELECT uri FROM ' . $this->tableName . ' WHERE lower(email)=lower(?)'; $stmt = $this->pdo->prepare($query); - $stmt->execute([ $value ]); + $stmt->execute([$value]); while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { // Checking if the principal is in the prefix diff --git a/vendor/sabre/dav/lib/DAVACL/PrincipalCollection.php b/vendor/sabre/dav/lib/DAVACL/PrincipalCollection.php index d8a90153a..ee5b88a90 100644 --- a/vendor/sabre/dav/lib/DAVACL/PrincipalCollection.php +++ b/vendor/sabre/dav/lib/DAVACL/PrincipalCollection.php @@ -57,7 +57,7 @@ class PrincipalCollection extends AbstractPrincipalCollection implements IExtend * * @param string $name * @param MkCol $mkCol - * @throws Exception\InvalidResourceType + * @throws InvalidResourceType * @return void */ function createExtendedCollection($name, MkCol $mkCol) { diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Property/Acl.php b/vendor/sabre/dav/lib/DAVACL/Xml/Property/Acl.php index 9f5e40df1..0e1c30ccf 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Property/Acl.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Property/Acl.php @@ -78,12 +78,12 @@ class Acl implements Element, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -149,7 +149,7 @@ class Acl implements Element, HtmlOutput { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Property/AclRestrictions.php b/vendor/sabre/dav/lib/DAVACL/Xml/Property/AclRestrictions.php index f669cc5e1..8d5854c23 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Property/AclRestrictions.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Property/AclRestrictions.php @@ -2,8 +2,8 @@ namespace Sabre\DAVACL\Xml\Property; -use Sabre\Xml\XmlSerializable; use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * AclRestrictions property @@ -17,12 +17,12 @@ use Sabre\Xml\Writer; class AclRestrictions implements XmlSerializable { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Property/CurrentUserPrivilegeSet.php b/vendor/sabre/dav/lib/DAVACL/Xml/Property/CurrentUserPrivilegeSet.php index 0a95eb2b7..74c09cee1 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Property/CurrentUserPrivilegeSet.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Property/CurrentUserPrivilegeSet.php @@ -41,12 +41,12 @@ class CurrentUserPrivilegeSet implements Element, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -99,7 +99,7 @@ class CurrentUserPrivilegeSet implements Element, HtmlOutput { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Property/Principal.php b/vendor/sabre/dav/lib/DAVACL/Xml/Property/Principal.php index d32249d8b..04d22165d 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Property/Principal.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Property/Principal.php @@ -85,12 +85,12 @@ class Principal extends DAV\Xml\Property\Href { /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Property/SupportedPrivilegeSet.php b/vendor/sabre/dav/lib/DAVACL/Xml/Property/SupportedPrivilegeSet.php index 55e7783ae..b963cc8c3 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Property/SupportedPrivilegeSet.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Property/SupportedPrivilegeSet.php @@ -4,8 +4,8 @@ namespace Sabre\DAVACL\Xml\Property; use Sabre\DAV\Browser\HtmlOutput; use Sabre\DAV\Browser\HtmlOutputHelper; -use Sabre\Xml\XmlSerializable; use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; /** * SupportedPrivilegeSet property @@ -53,12 +53,12 @@ class SupportedPrivilegeSet implements XmlSerializable, HtmlOutput { } /** - * The xmlSerialize metod is called during xml writing. + * The xmlSerialize method is called during xml writing. * * Use the $writer argument to write its own xml serialization. * * An important note: do _not_ create a parent element. Any element - * implementing XmlSerializble should only ever write what's considered + * implementing XmlSerializable should only ever write what's considered * its 'inner xml'. * * The parent of the current element is responsible for writing a @@ -73,7 +73,7 @@ class SupportedPrivilegeSet implements XmlSerializable, HtmlOutput { */ function xmlSerialize(Writer $writer) { - $this->serializePriv($writer, '{DAV:}all', [ 'aggregates' => $this->privileges]); + $this->serializePriv($writer, '{DAV:}all', ['aggregates' => $this->privileges]); } @@ -114,7 +114,7 @@ class SupportedPrivilegeSet implements XmlSerializable, HtmlOutput { ob_start(); echo "<ul class=\"tree\">"; - $traverse('{DAV:}all', [ 'aggregates' => $this->getValue() ]); + $traverse('{DAV:}all', ['aggregates' => $this->getValue()]); echo "</ul>\n"; return ob_get_clean(); @@ -129,6 +129,7 @@ class SupportedPrivilegeSet implements XmlSerializable, HtmlOutput { * This is a recursive function. * * @param Writer $writer + * @param string $privName * @param array $privilege * @return void */ diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Request/AclPrincipalPropSetReport.php b/vendor/sabre/dav/lib/DAVACL/Xml/Request/AclPrincipalPropSetReport.php index f01c1e6ab..0aa2f29a5 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Request/AclPrincipalPropSetReport.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Request/AclPrincipalPropSetReport.php @@ -2,9 +2,9 @@ namespace Sabre\DAVACL\Xml\Request; -use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Reader; use Sabre\Xml\Deserializer; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * AclPrincipalPropSet request parser. @@ -24,7 +24,7 @@ class AclPrincipalPropSetReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Request/ExpandPropertyReport.php b/vendor/sabre/dav/lib/DAVACL/Xml/Request/ExpandPropertyReport.php index 3f535e301..a9938ba5b 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Request/ExpandPropertyReport.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Request/ExpandPropertyReport.php @@ -35,7 +35,7 @@ class ExpandPropertyReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalMatchReport.php b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalMatchReport.php index 5c4e88189..1be15ab2d 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalMatchReport.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalMatchReport.php @@ -2,9 +2,9 @@ namespace Sabre\DAVACL\Xml\Request; -use Sabre\Xml\XmlDeserializable; -use Sabre\Xml\Reader; use Sabre\Xml\Deserializer; +use Sabre\Xml\Reader; +use Sabre\Xml\XmlDeserializable; /** * PrincipalMatchReport request parser. @@ -55,7 +55,7 @@ class PrincipalMatchReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalPropertySearchReport.php b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalPropertySearchReport.php index 1e7aa4481..b0cf0e408 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalPropertySearchReport.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalPropertySearchReport.php @@ -2,9 +2,9 @@ namespace Sabre\DAVACL\Xml\Request; +use Sabre\DAV\Exception\BadRequest; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; /** * PrincipalSearchPropertySetReport request parser. @@ -56,7 +56,7 @@ class PrincipalPropertySearchReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalSearchPropertySetReport.php b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalSearchPropertySetReport.php index ade157b19..64d1f7f86 100644 --- a/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalSearchPropertySetReport.php +++ b/vendor/sabre/dav/lib/DAVACL/Xml/Request/PrincipalSearchPropertySetReport.php @@ -2,9 +2,9 @@ namespace Sabre\DAVACL\Xml\Request; +use Sabre\DAV\Exception\BadRequest; use Sabre\Xml\Reader; use Sabre\Xml\XmlDeserializable; -use Sabre\DAV\Exception\BadRequest; /** * PrincipalSearchPropertySetReport request parser. @@ -23,7 +23,7 @@ class PrincipalSearchPropertySetReport implements XmlDeserializable { /** * The deserialize method is called during xml parsing. * - * This method is called statictly, this is because in theory this method + * This method is called statically, this is because in theory this method * may be used as a type of constructor, or factory method. * * Often you want to return an instance of the current class, but you are diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php index 2a00f7925..406dbe0e8 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php @@ -280,7 +280,7 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { ], ]; - $result = $backend->getMultipleCalendarObjects($returnedId, [ 'id-1', 'id-2' ]); + $result = $backend->getMultipleCalendarObjects($returnedId, ['id-1', 'id-2']); foreach ($check as $index => $props) { @@ -441,7 +441,7 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { /** * @depends testCreateCalendarObject */ - function testCreateCalendarObjectInfiniteReccurence() { + function testCreateCalendarObjectInfiniteRecurrence() { $backend = new PDO($this->pdo); $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); @@ -470,7 +470,7 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { /** * @depends testCreateCalendarObject */ - function testCreateCalendarObjectEndingReccurence() { + function testCreateCalendarObjectEndingRecurrence() { $backend = new PDO($this->pdo); $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); @@ -1246,8 +1246,8 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { $calendar['id'], [ new Sharee([ - 'href' => 'mailto:user@example.org', - 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, + 'href' => 'mailto:user@example.org', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, ]) ] ); @@ -1263,8 +1263,8 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { $calendar['id'], [ new Sharee([ - 'href' => 'principals/user2', - 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, + 'href' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, ]) ] ); diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php index d4dcc07dc..cc665cd8f 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php @@ -2,8 +2,8 @@ namespace Sabre\CalDAV\Backend; -use Sabre\DAV; use Sabre\CalDAV; +use Sabre\DAV; class Mock extends AbstractBackend { diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php index 0d98922ff..c92cde661 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php @@ -114,7 +114,7 @@ class CalendarObjectTest extends \PHPUnit_Framework_TestCase { $obj = $children[0]; $obj->delete(); - $children2 = $this->calendar->getChildren(); + $children2 = $this->calendar->getChildren(); $this->assertEquals(count($children) - 1, count($children2)); } diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php index 4c2558a9b..f3305163b 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php @@ -21,6 +21,9 @@ ICS; } /** + * @param string $icalObject + * @param array $filters + * @param int $outcome * @dataProvider provider */ function testValid($icalObject, $filters, $outcome) { diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php index 7a756774f..7604c7f4c 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php @@ -11,11 +11,11 @@ require_once 'Sabre/HTTP/ResponseMock.php'; class FreeBusyReportTest extends \PHPUnit_Framework_TestCase { /** - * @var Sabre\CalDAV\Plugin + * @var Plugin */ protected $plugin; /** - * @var Sabre\DAV\Server + * @var DAV\Server */ protected $server; diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php index 9719529fb..75412577e 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php @@ -3,9 +3,9 @@ namespace Sabre\CalDAV; use Sabre\DAV; +use Sabre\DAVACL; use Sabre\HTTP; use Sabre\VObject; -use Sabre\DAVACL; class ICSExportPluginTest extends \Sabre\DAVServerTest { diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php index 8d538dee5..859f6aa0c 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php @@ -2,11 +2,11 @@ namespace Sabre\CalDAV; -use Sabre\DAVACL; -use Sabre\DAV; -use Sabre\HTTP; use DateTime; use DateTimeZone; +use Sabre\DAV; +use Sabre\DAVACL; +use Sabre\HTTP; class PluginTest extends \PHPUnit_Framework_TestCase { diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php index 6e9e88419..9589176a3 100644 --- a/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php @@ -194,8 +194,8 @@ RRR; $this->assertEquals( [ new Sharee([ - 'href' => 'mailto:joe@example.org', - 'properties' => [ + 'href' => 'mailto:joe@example.org', + 'properties' => [ '{DAV:}displayname' => 'Joe Shmoe', ], 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php index 2c3171bf3..f8da38a16 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php @@ -2,8 +2,8 @@ namespace Sabre\CardDAV; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; require_once 'Sabre/CardDAV/AbstractPluginTest.php'; require_once 'Sabre/HTTP/ResponseMock.php'; @@ -288,14 +288,14 @@ class AddressBookQueryTest extends AbstractPluginTest { ); $request->setBody( -'<?xml version="1.0"?> + '<?xml version="1.0"?> <c:addressbook-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav"> <d:prop> <c:address-data content-type="application/vcard+json" /> <d:getetag /> </d:prop> </c:addressbook-query>' - ); + ); $response = new HTTP\ResponseMock(); @@ -305,6 +305,51 @@ class AddressBookQueryTest extends AbstractPluginTest { $this->server->exec(); $this->assertEquals(415, $response->status, 'Incorrect status code. Full response body:' . $response->body); + } + + function testAddressBookProperties() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book3', + ['Depth' => '1'] + ); + + $request->setBody( + '<?xml version="1.0"?> +<c:addressbook-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav"> + <d:prop> + <c:address-data> + <c:prop name="FN"/> + <c:prop name="BDAY"/> + </c:address-data> + <d:getetag /> + </d:prop> +</c:addressbook-query>' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book3/card3' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\r\nVERSION:3.0\r\nUID:12345\r\nFN:Test-Card\r\nEND:VCARD\r\n", + ], + ], + ], $result); } } diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php index 1a36fd10c..1f0064dd3 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php @@ -85,7 +85,7 @@ class AddressBookTest extends \PHPUnit_Framework_TestCase { function testDelete() { $this->ab->delete(); - $this->assertEquals([], $this->backend->addressBooks); + $this->assertEquals(1, count($this->backend->addressBooks)); } @@ -175,7 +175,7 @@ class AddressBookTest extends \PHPUnit_Framework_TestCase { $backend = new Backend\PDO( $this->getPDO() ); - $ab = new AddressBook($backend, [ 'id' => 1, '{DAV:}sync-token' => 2]); + $ab = new AddressBook($backend, ['id' => 1, '{DAV:}sync-token' => 2]); $this->assertEquals(2, $ab->getSyncToken()); } @@ -187,7 +187,7 @@ class AddressBookTest extends \PHPUnit_Framework_TestCase { $backend = new Backend\PDO( $this->getPDO() ); - $ab = new AddressBook($backend, [ 'id' => 1, '{http://sabredav.org/ns}sync-token' => 2]); + $ab = new AddressBook($backend, ['id' => 1, '{http://sabredav.org/ns}sync-token' => 2]); $this->assertEquals(2, $ab->getSyncToken()); } diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php index 840b898e8..8638dc74a 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php @@ -20,6 +20,12 @@ class Mock extends AbstractBackend { 'principaluri' => 'principals/user1', '{DAV:}displayname' => 'd-name', ], + [ + 'id' => 'bar', + 'uri' => 'book3', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'd-name', + ], ]; $card2 = fopen('php://memory', 'r+'); @@ -30,6 +36,9 @@ class Mock extends AbstractBackend { 'card1' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", 'card2' => $card2, ], + 'bar' => [ + 'card3' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD", + ], ]; } @@ -58,7 +67,7 @@ class Mock extends AbstractBackend { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $addressBookId * @param \Sabre\DAV\PropPatch $propPatch @@ -117,7 +126,7 @@ class Mock extends AbstractBackend { * calculating them. If they are specified, you can also ommit carddata. * This may speed up certain requests, especially with large cards. * - * @param mixed $addressbookId + * @param mixed $addressBookId * @return array */ function getCards($addressBookId) { diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php index d79239d0f..2d57c6ae7 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php @@ -2,8 +2,8 @@ namespace Sabre\CardDAV; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; require_once 'Sabre/HTTP/ResponseMock.php'; diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php index 0ba4fd669..d4bc48098 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php @@ -2,8 +2,8 @@ namespace Sabre\CardDAV; -use Sabre\HTTP; use Sabre\DAV\PropFind; +use Sabre\HTTP; class SogoStripContentTypeTest extends \Sabre\DAVServerTest { diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php index 57ac21b4a..03c468f86 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php @@ -7,6 +7,11 @@ require_once 'Sabre/CardDAV/AbstractPluginTest.php'; class ValidateFilterTest extends AbstractPluginTest { /** + * @param string $input + * @param array $filters + * @param string $test + * @param bool $result + * @param string|null $message * @dataProvider data */ function testFilter($input, $filters, $test, $result, $message = null) { diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php index dda8a0c37..acba2cfc8 100644 --- a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php @@ -3,8 +3,8 @@ namespace Sabre\CardDAV; use Sabre\DAV; -use Sabre\HTTP; use Sabre\DAVACL; +use Sabre\HTTP; require_once 'Sabre/HTTP/ResponseMock.php'; @@ -293,10 +293,10 @@ VCF; $response = $this->request($request, 204); $expected = [ - 'uri' => 'blabla.vcf', - 'carddata' => $body, - 'size' => strlen($body), - 'etag' => '"' . md5($body) . '"', + 'uri' => 'blabla.vcf', + 'carddata' => $body, + 'size' => strlen($body), + 'etag' => '"' . md5($body) . '"', ]; $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1', 'blabla.vcf')); diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php index b30b3f143..369bc249e 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php @@ -76,6 +76,8 @@ class Mock implements BackendInterface { * append your own WWW-Authenticate header instead of overwriting the * existing one. * + * @param RequestInterface $request + * @param ResponseInterface $response * @return void */ function challenge(RequestInterface $request, ResponseInterface $response) { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php index b566dd757..743446127 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Auth; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; class PluginTest extends \PHPUnit_Framework_TestCase { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php index 4cf27dfaa..687f61e2f 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php @@ -224,7 +224,7 @@ XML; XML; $client->response = new Response(207, [], $responseBody); - $result = $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null], 1); + $result = $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); $this->assertTrue($result); $request = $client->request; $this->assertEquals('PROPPATCH', $request->getMethod()); @@ -246,7 +246,7 @@ XML; ]); $client->response = new Response(403, [], ''); - $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null], 1); + $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); } @@ -276,7 +276,7 @@ XML; XML; $client->response = new Response(207, [], $responseBody); - $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null], 1); + $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); } diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php index 8788475cb..174a561b5 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Exception; -use Sabre\DAV; use DOMDocument; +use Sabre\DAV; class LockedTest extends \PHPUnit_Framework_TestCase { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php b/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php index edd09e634..ba2cf3dc1 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php @@ -99,7 +99,7 @@ class Issue33Test extends \PHPUnit_Framework_TestCase { $server->sapi = new HTTP\SapiMock(); $server->exec(); - $this->assertTrue(file_exists(SABRE_TEMPDIR . '/issue33/' . urldecode('%C3%A0fo%C3%B3'))); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/issue33/' . urldecode('%C3%A0fo%C3%B3'))); } diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php index f08f19da5..1111db5b5 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Locks; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; require_once 'Sabre/HTTP/ResponseMock.php'; require_once 'Sabre/TestUtil.php'; @@ -112,9 +112,9 @@ class MSWordTest extends \PHPUnit_Framework_TestCase { function getPutRequest($lockToken) { $request = HTTP\Sapi::createFromServerArray([ - 'REQUEST_METHOD' => 'PUT', - 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', - 'HTTP_IF' => 'If: (' . $lockToken . ')', + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + 'HTTP_IF' => 'If: (' . $lockToken . ')', ]); $request->setBody('FAKE BODY'); return $request; diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php index 6511d4e7d..dbbf6757a 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php @@ -2,8 +2,8 @@ namespace Sabre\DAV\Locks; -use Sabre\HTTP; use Sabre\DAV; +use Sabre\HTTP; require_once 'Sabre/DAV/AbstractServer.php'; @@ -168,7 +168,7 @@ class PluginTest extends DAV\AbstractServer { $this->response = new HTTP\ResponseMock(); $this->server->httpResponse = $this->response; - $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . ')' ]); + $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . ')']); $request->setBody(''); $this->server->httpRequest = $request; @@ -203,7 +203,7 @@ class PluginTest extends DAV\AbstractServer { $this->response = new HTTP\ResponseMock(); $this->server->httpResponse = $this->response; - $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . 'foobar) (<opaquelocktoken:anotherbadtoken>)' ]); + $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . 'foobar) (<opaquelocktoken:anotherbadtoken>)']); $request->setBody(''); $this->server->httpRequest = $request; diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php index 6ccab4f66..fded5e474 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php @@ -30,6 +30,7 @@ class Collection extends DAV\Collection { * * @param string $name * @param array $children + * @param Collection $parent * @return void */ function __construct($name, array $children = [], Collection $parent = null) { @@ -122,6 +123,8 @@ class Collection extends DAV\Collection { /** * Adds an already existing node to this collection. + * + * @param \Sabre\DAV\INode $node */ function addNode(\Sabre\DAV\INode $node) { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php index 23855e3c5..a624b6b6b 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php @@ -24,7 +24,9 @@ class File extends DAV\File { * Creates the object * * @param string $name - * @param array $children + * @param resource $contents + * @param Collection $parent + * @param int $lastModified * @return void */ function __construct($name, $contents, Collection $parent = null, $lastModified = -1) { @@ -57,6 +59,7 @@ class File extends DAV\File { /** * Changes the name of the node. * + * @param string $name * @return void */ function setName($name) { @@ -70,7 +73,7 @@ class File extends DAV\File { * * The data argument is a readable stream resource. * - * After a succesful put operation, you may choose to return an ETag. The + * After a successful put operation, you may choose to return an ETag. The * etag must always be surrounded by double-quotes. These quotes must * appear in the actual string you're returning. * diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php index ca8ca3f6e..2c6274173 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php @@ -38,6 +38,11 @@ class SpecificationTest extends \PHPUnit_Framework_TestCase { } /** + * @param string $headerValue + * @param string $httpStatus + * @param string $endResult + * @param int $contentLength + * * @dataProvider data */ function testUpdateRange($headerValue, $httpStatus, $endResult, $contentLength = 4) { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php index 4c576f108..42759647a 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php @@ -39,8 +39,8 @@ class ServerEventsTest extends AbstractServer { $this->server->on('afterResponse', [$mock, 'afterResponseCallback']); $this->server->httpRequest = HTTP\Sapi::createFromServerArray([ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/test.txt', ]); $this->server->exec(); @@ -118,8 +118,8 @@ class ServerEventsTest extends AbstractServer { ); } catch (Exception $e) {} - $this->assertEquals(2, $k); - + // Fun fact, PHP 7.1 changes the order when sorting-by-callback. + $this->assertTrue($k >= 2 && $k <= 3); } diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php index bafbef6e4..81224d687 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php @@ -144,7 +144,7 @@ class ServerRangeTest extends \Sabre\DAVServerTest { 'Content-Length' => [4], 'Content-Range' => ['bytes 2-5/12'], // 'ETag' => ['"' . md5('Test contents') . '"'], - 'Last-Modified' => [$this->lastModified], + 'Last-Modified' => [$this->lastModified], ], $response->getHeaders() ); diff --git a/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php b/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php index 8888f0276..e98fe9048 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php @@ -5,6 +5,13 @@ namespace Sabre\DAV; class StringUtilTest extends \PHPUnit_Framework_TestCase { /** + * @param string $haystack + * @param string $needle + * @param string $collation + * @param string $matchType + * @param string $result + * @throws Exception\BadRequest + * * @dataProvider dataset */ function testTextMatch($haystack, $needle, $collation, $matchType, $result) { diff --git a/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php index ad33200c8..e719e38d5 100644 --- a/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php +++ b/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php @@ -200,8 +200,8 @@ class TreeFileTester extends File implements IProperties { * To update specific properties, call the 'handle' method on this object. * Read the PropPatch documentation for more information. * - * @param array $mutations - * @return bool|array + * @param PropPatch $propPatch + * @return void */ function propPatch(PropPatch $propPatch) { @@ -220,6 +220,7 @@ class TreeMultiGetTester extends TreeDirectoryTester implements IMultiGet { * * If any children are not found, you do not have to return them. * + * @param array $paths * @return array */ function getMultipleChildren(array $paths) { diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php index afb094a39..1464f4c26 100644 --- a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php @@ -128,7 +128,7 @@ class Mock extends AbstractBackend { * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * - * Read the PropPatch documenation for more info and examples. + * Read the PropPatch documentation for more info and examples. * * @param string $path * @param \Sabre\DAV\PropPatch $propPatch diff --git a/vendor/sabre/http/.travis.yml b/vendor/sabre/http/.travis.yml index 490e42e1e..8ae84d90f 100644 --- a/vendor/sabre/http/.travis.yml +++ b/vendor/sabre/http/.travis.yml @@ -4,6 +4,7 @@ php: - 5.5 - 5.6 - 7 + - 7.1 - hhvm matrix: @@ -16,7 +17,8 @@ env: before_script: - - composer self-update + - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini +# - composer self-update - composer update --prefer-source $PREFER_LOWEST script: diff --git a/vendor/sabre/http/CHANGELOG.md b/vendor/sabre/http/CHANGELOG.md index 9a751d8fb..63d85afe3 100644 --- a/vendor/sabre/http/CHANGELOG.md +++ b/vendor/sabre/http/CHANGELOG.md @@ -1,19 +1,25 @@ ChangeLog ========= +4.2.2 (2017-01-02) +------------------ + +* #72: Handling clients that send invalid `Content-Length` headers. + + 4.2.1 (2016-01-06) ------------------ * #56: `getBodyAsString` now returns at most as many bytes as the contents of the `Content-Length` header. This allows users to pass much larger strings without having to copy and truncate them. +* The client now sets a default `User-Agent` header identifying this library. 4.2.0 (2016-01-04) ------------------ * This package now supports sabre/event 3.0. -* The client now sets a default `User-Agent` header identifying this library. 4.1.0 (2015-09-04) diff --git a/vendor/sabre/http/LICENSE b/vendor/sabre/http/LICENSE index 19812ad7a..864041b22 100644 --- a/vendor/sabre/http/LICENSE +++ b/vendor/sabre/http/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2009-2016 fruux GmbH (https://fruux.com/) +Copyright (C) 2009-2017 fruux GmbH (https://fruux.com/) All rights reserved. diff --git a/vendor/sabre/http/composer.json b/vendor/sabre/http/composer.json index b061194cf..507d5d28d 100644 --- a/vendor/sabre/http/composer.json +++ b/vendor/sabre/http/composer.json @@ -7,6 +7,7 @@ "require" : { "php" : ">=5.4", "ext-mbstring" : "*", + "ext-ctype" : "*", "sabre/event" : ">=1.0.0,<4.0.0", "sabre/uri" : "~1.0" }, diff --git a/vendor/sabre/http/lib/Message.php b/vendor/sabre/http/lib/Message.php index 5c6887d8a..45bd18398 100644 --- a/vendor/sabre/http/lib/Message.php +++ b/vendor/sabre/http/lib/Message.php @@ -75,12 +75,11 @@ abstract class Message implements MessageInterface { return ''; } $contentLength = $this->getHeader('Content-Length'); - if (null === $contentLength) { - return stream_get_contents($body); - } else { + if (is_int($contentLength) || ctype_digit($contentLength)) { return stream_get_contents($body, $contentLength); + } else { + return stream_get_contents($body); } - } /** @@ -189,7 +188,7 @@ abstract class Message implements MessageInterface { /** * Updates a HTTP header. * - * The case-sensitity of the name value must be retained as-is. + * The case-sensitivity of the name value must be retained as-is. * * If the header already existed, it will be overwritten. * @@ -270,10 +269,11 @@ abstract class Message implements MessageInterface { /** * Removes a HTTP header. * - * The specified header name must be treated as case-insenstive. + * The specified header name must be treated as case-insensitive. * This method should return true if the header was successfully deleted, * and false if the header did not exist. * + * @param string $name * @return bool */ function removeHeader($name) { diff --git a/vendor/sabre/http/lib/MessageDecoratorTrait.php b/vendor/sabre/http/lib/MessageDecoratorTrait.php index f104af38d..1cb32da22 100644 --- a/vendor/sabre/http/lib/MessageDecoratorTrait.php +++ b/vendor/sabre/http/lib/MessageDecoratorTrait.php @@ -144,7 +144,7 @@ trait MessageDecoratorTrait { /** * Updates a HTTP header. * - * The case-sensitity of the name value must be retained as-is. + * The case-sensitivity of the name value must be retained as-is. * * If the header already existed, it will be overwritten. * @@ -210,15 +210,16 @@ trait MessageDecoratorTrait { /** * Removes a HTTP header. * - * The specified header name must be treated as case-insenstive. + * The specified header name must be treated as case-insensitive. * This method should return true if the header was successfully deleted, * and false if the header did not exist. * + * @param string $name * @return bool */ function removeHeader($name) { - $this->inner->removeHeader($name); + return $this->inner->removeHeader($name); } diff --git a/vendor/sabre/http/lib/MessageInterface.php b/vendor/sabre/http/lib/MessageInterface.php index 55d8485c1..df55beb2f 100644 --- a/vendor/sabre/http/lib/MessageInterface.php +++ b/vendor/sabre/http/lib/MessageInterface.php @@ -44,7 +44,7 @@ interface MessageInterface { /** * Updates the body resource with a new stream. * - * @param resource $body + * @param resource|string $body * @return void */ function setBody($body); @@ -153,6 +153,7 @@ interface MessageInterface { * This method should return true if the header was successfully deleted, * and false if the header did not exist. * + * @param string $name * @return bool */ function removeHeader($name); diff --git a/vendor/sabre/http/lib/Request.php b/vendor/sabre/http/lib/Request.php index 8bcaf32a6..dfa3d5b48 100644 --- a/vendor/sabre/http/lib/Request.php +++ b/vendor/sabre/http/lib/Request.php @@ -301,7 +301,7 @@ class Request extends Message implements RequestInterface { foreach ($value as $v) { if ($key === 'Authorization') { list($v) = explode(' ', $v, 2); - $v .= ' REDACTED'; + $v .= ' REDACTED'; } $out .= $key . ": " . $v . "\r\n"; } diff --git a/vendor/sabre/http/lib/Response.php b/vendor/sabre/http/lib/Response.php index d2ba6d40d..01920d8d9 100644 --- a/vendor/sabre/http/lib/Response.php +++ b/vendor/sabre/http/lib/Response.php @@ -100,7 +100,6 @@ class Response extends Message implements ResponseInterface { * @param string|int $status * @param array $headers * @param resource $body - * @return void */ function __construct($status = null, array $headers = null, $body = null) { @@ -145,7 +144,7 @@ class Response extends Message implements ResponseInterface { * added. * * @param string|int $status - * @throws \InvalidArgumentExeption + * @throws \InvalidArgumentException * @return void */ function setStatus($status) { diff --git a/vendor/sabre/http/lib/ResponseInterface.php b/vendor/sabre/http/lib/ResponseInterface.php index c0ecc35ae..411cdc06c 100644 --- a/vendor/sabre/http/lib/ResponseInterface.php +++ b/vendor/sabre/http/lib/ResponseInterface.php @@ -37,7 +37,7 @@ interface ResponseInterface extends MessageInterface { * added. * * @param string|int $status - * @throws \InvalidArgumentExeption + * @throws \InvalidArgumentException * @return void */ function setStatus($status); diff --git a/vendor/sabre/http/lib/URLUtil.php b/vendor/sabre/http/lib/URLUtil.php index 474856348..85c0e1150 100644 --- a/vendor/sabre/http/lib/URLUtil.php +++ b/vendor/sabre/http/lib/URLUtil.php @@ -10,7 +10,7 @@ use Sabre\URI; * Note: this class is deprecated. All its functionality moved to functions.php * or sabre\uri. * - * @deprectated + * @deprecated * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License diff --git a/vendor/sabre/http/lib/Util.php b/vendor/sabre/http/lib/Util.php index 83bde50a4..e3f13a645 100644 --- a/vendor/sabre/http/lib/Util.php +++ b/vendor/sabre/http/lib/Util.php @@ -31,7 +31,7 @@ class Util { * Deprecated! Use negotiateContentType. * * @deprecated Use \Sabre\HTTP\NegotiateContentType - * @param string|null $acceptHeader + * @param string|null $acceptHeaderValue * @param array $availableOptions * @return string|null */ diff --git a/vendor/sabre/http/lib/Version.php b/vendor/sabre/http/lib/Version.php index 789ee4543..a5a427405 100644 --- a/vendor/sabre/http/lib/Version.php +++ b/vendor/sabre/http/lib/Version.php @@ -14,6 +14,6 @@ class Version { /** * Full version number */ - const VERSION = '4.2.1'; + const VERSION = '4.2.2'; } diff --git a/vendor/sabre/http/lib/functions.php b/vendor/sabre/http/lib/functions.php index 1ec123f2e..d94119623 100644 --- a/vendor/sabre/http/lib/functions.php +++ b/vendor/sabre/http/lib/functions.php @@ -79,7 +79,7 @@ function toDate(DateTime $dateTime) { // We need to clone it, as we don't want to affect the existing // DateTime. $dateTime = clone $dateTime; - $dateTime->setTimeZone(new \DateTimeZone('GMT')); + $dateTime->setTimezone(new \DateTimeZone('GMT')); return $dateTime->format('D, d M Y H:i:s \G\M\T'); } @@ -216,7 +216,7 @@ function negotiateContentType($acceptHeaderValue, array $availableOptions) { * Parameters are currently discarded. There's no known prefer value that * uses them. * - * @param string|string[] $header + * @param string|string[] $input * @return array */ function parsePrefer($input) { diff --git a/vendor/sabre/uri/.travis.yml b/vendor/sabre/uri/.travis.yml index f7d1a0657..75c8270df 100644 --- a/vendor/sabre/uri/.travis.yml +++ b/vendor/sabre/uri/.travis.yml @@ -3,8 +3,8 @@ php: - 5.4 - 5.5 - 5.6 - - hhvm - 7 + - 7.1 script: - ./bin/phpunit --configuration tests/phpunit.xml.dist diff --git a/vendor/sabre/uri/CHANGELOG.md b/vendor/sabre/uri/CHANGELOG.md index 9fa510dc2..92aaa7507 100644 --- a/vendor/sabre/uri/CHANGELOG.md +++ b/vendor/sabre/uri/CHANGELOG.md @@ -1,6 +1,29 @@ ChangeLog ========= +1.2.1 (2017-02-20) +------------------ + +* #16: Correctly parse urls that are only a fragment `#`. + + +1.2.0 (2016-12-06) +------------------ + +* Now throwing `InvalidUriException` if a uri passed to the `parse` function + is invalid or could not be parsed. +* #11: Fix support for URIs that start with a triple slash. PHP's `parse_uri()` + doesn't support them, so we now have a pure-php fallback in case it fails. +* #9: Fix support for relative URI's that have a non-uri encoded colon `:` in + them. + + +1.1.1 (2016-10-27) +------------------ + +* #10: Correctly support file:// URIs in the build() method. (@yuloh) + + 1.1.0 (2016-03-07) ------------------ diff --git a/vendor/sabre/uri/LICENSE b/vendor/sabre/uri/LICENSE index 9a3a91946..087996be7 100644 --- a/vendor/sabre/uri/LICENSE +++ b/vendor/sabre/uri/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2014-2016 fruux GmbH (https://fruux.com/) +Copyright (C) 2014-2017 fruux GmbH (https://fruux.com/) All rights reserved. diff --git a/vendor/sabre/uri/README.md b/vendor/sabre/uri/README.md index 76f55d8e4..aa21bfe06 100644 --- a/vendor/sabre/uri/README.md +++ b/vendor/sabre/uri/README.md @@ -25,14 +25,6 @@ Further reading * [Usage][8] -Build status ------------- - -| branch | status | -| ------ | ------ | -| master | [![Build Status](https://travis-ci.org/fruux/sabre-uri.svg?branch=master)](https://travis-ci.org/fruux/sabre-uri) | - - Questions? ---------- diff --git a/vendor/sabre/uri/composer.json b/vendor/sabre/uri/composer.json index 7b48acb71..49d69e723 100644 --- a/vendor/sabre/uri/composer.json +++ b/vendor/sabre/uri/composer.json @@ -32,8 +32,8 @@ } }, "require-dev": { - "sabre/cs": "~0.0.1", - "phpunit/phpunit" : "*" + "sabre/cs": "~1.0.0", + "phpunit/phpunit" : ">=4.0,<6.0" }, "config" : { "bin-dir" : "bin/" diff --git a/vendor/sabre/uri/lib/InvalidUriException.php b/vendor/sabre/uri/lib/InvalidUriException.php new file mode 100644 index 000000000..0385fd462 --- /dev/null +++ b/vendor/sabre/uri/lib/InvalidUriException.php @@ -0,0 +1,17 @@ +<?php + +namespace Sabre\Uri; + +/** + * Invalid Uri + * + * This is thrown when an attempt was made to use Sabre\Uri parse a uri that + * it could not. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (https://evertpot.com/) + * @license http://sabre.io/license/ + */ +class InvalidUriException extends \Exception { + +} diff --git a/vendor/sabre/uri/lib/Version.php b/vendor/sabre/uri/lib/Version.php index 88678d4d5..fa544538b 100644 --- a/vendor/sabre/uri/lib/Version.php +++ b/vendor/sabre/uri/lib/Version.php @@ -14,6 +14,6 @@ class Version { /** * Full version number */ - const VERSION = '1.1.0'; + const VERSION = '1.2.1'; } diff --git a/vendor/sabre/uri/lib/functions.php b/vendor/sabre/uri/lib/functions.php index 06181aef0..39b4a6f08 100644 --- a/vendor/sabre/uri/lib/functions.php +++ b/vendor/sabre/uri/lib/functions.php @@ -45,8 +45,8 @@ function resolve($basePath, $newPath) { $newParts = []; $newParts['scheme'] = $pick('scheme'); - $newParts['host'] = $pick('host'); - $newParts['port'] = $pick('port'); + $newParts['host'] = $pick('host'); + $newParts['port'] = $pick('port'); $path = ''; if ($delta['path']) { @@ -193,8 +193,13 @@ function parse($uri) { $uri ); + $result = parse_url($uri); + if (!$result) { + $result = _parse_fallback($uri); + } + return - parse_url($uri) + [ + $result + [ 'scheme' => null, 'host' => null, 'path' => null, @@ -233,7 +238,7 @@ function build(array $parts) { $uri = $parts['scheme'] . ':'; } - if ($authority) { + if ($authority || (!empty($parts['scheme']) && $parts['scheme'] === 'file')) { // No scheme, but there is a host. $uri .= '//' . $authority; @@ -280,3 +285,89 @@ function split($path) { return [null,null]; } + +/** + * This function is another implementation of parse_url, except this one is + * fully written in PHP. + * + * The reason is that the PHP bug team is not willing to admit that there are + * bugs in the parse_url implementation. + * + * This function is only called if the main parse method fails. It's pretty + * crude and probably slow, so the original parse_url is usually preferred. + * + * @param string $uri + * @return array + */ +function _parse_fallback($uri) { + + // Normally a URI must be ASCII, however. However, often it's not and + // parse_url might corrupt these strings. + // + // For that reason we take any non-ascii characters from the uri and + // uriencode them first. + $uri = preg_replace_callback( + '/[^[:ascii:]]/u', + function($matches) { + return rawurlencode($matches[0]); + }, + $uri + ); + + $result = [ + 'scheme' => null, + 'host' => null, + 'port' => null, + 'user' => null, + 'path' => null, + 'fragment' => null, + 'query' => null, + ]; + + if (preg_match('% ^([A-Za-z][A-Za-z0-9+-\.]+): %x', $uri, $matches)) { + + $result['scheme'] = $matches[1]; + // Take what's left. + $uri = substr($uri, strlen($result['scheme']) + 1); + + } + + // Taking off a fragment part + if (strpos($uri, '#') !== false) { + list($uri, $result['fragment']) = explode('#', $uri, 2); + } + // Taking off the query part + if (strpos($uri, '?') !== false) { + list($uri, $result['query']) = explode('?', $uri, 2); + } + + if (substr($uri, 0, 3) === '///') { + // The triple slash uris are a bit unusual, but we have special handling + // for them. + $result['path'] = substr($uri, 2); + $result['host'] = ''; + } elseif (substr($uri, 0, 2) === '//') { + // Uris that have an authority part. + $regex = ' + %^ + // + (?: (?<user> [^:@]+) (: (?<pass> [^@]+)) @)? + (?<host> ( [^:/]* | \[ [^\]]+ \] )) + (?: : (?<port> [0-9]+))? + (?<path> / .*)? + $%x + '; + if (!preg_match($regex, $uri, $matches)) { + throw new InvalidUriException('Invalid, or could not parse URI'); + } + if ($matches['host']) $result['host'] = $matches['host']; + if ($matches['port']) $result['port'] = (int)$matches['port']; + if (isset($matches['path'])) $result['path'] = $matches['path']; + if ($matches['user']) $result['user'] = $matches['user']; + if ($matches['pass']) $result['pass'] = $matches['pass']; + } else { + $result['path'] = $uri; + } + + return $result; +} diff --git a/vendor/sabre/vobject/.travis.yml b/vendor/sabre/vobject/.travis.yml index b7266a878..3c5b32157 100644 --- a/vendor/sabre/vobject/.travis.yml +++ b/vendor/sabre/vobject/.travis.yml @@ -2,7 +2,8 @@ language: php php: - 5.5 - 5.6 - - 7 + - 7.0 + - 7.1 sudo: false diff --git a/vendor/sabre/vobject/CHANGELOG.md b/vendor/sabre/vobject/CHANGELOG.md index 4c72680f8..c8f4cb4be 100644 --- a/vendor/sabre/vobject/CHANGELOG.md +++ b/vendor/sabre/vobject/CHANGELOG.md @@ -1,6 +1,22 @@ ChangeLog ========= +4.1.2 (2016-12-15) +------------------ + +* #340: Support for `BYYEARDAY` recurrence when `FREQ=YEARLY`. (@PHPGangsta) +* #341: Support for `BYWEEKNO` recurrence when `FREQ=YEARLY`. (@PHPGangsta) +* Updated to the latest windows timezone data mappings. +* #344: Auto-detecting more Outlook 365-generated timezone identifiers. + (@jpirkey) +* #348: `FreeBusyGenerator` can now accept streams. +* Support sabre/xml 1.5 and 2.0. +* #355: Support `DateTimeInterface` in more places where only `DateTime` was + supported. (@gharlan). +* #351: Fixing an inclusive/exclusive problem with `isInTimeRange` and + `fastForward` with all-day events. (@strokyl, thanks you are brilliant). + + 4.1.1 (2016-07-15) ------------------ @@ -143,7 +159,7 @@ ChangeLog and `IntegerValue` to allow PHP 7 compatibility. -3.5.3 (????-??-??) +3.5.3 (2016-10-06) ------------------ * #331: Fix dealing with multiple overridden instances falling on the same diff --git a/vendor/sabre/vobject/bin/fetch_windows_zones.php b/vendor/sabre/vobject/bin/fetch_windows_zones.php index 1b1fdc37c..3f2a00f7a 100755 --- a/vendor/sabre/vobject/bin/fetch_windows_zones.php +++ b/vendor/sabre/vobject/bin/fetch_windows_zones.php @@ -36,7 +36,7 @@ fwrite($f, " *\n"); fwrite($f, " * Last update: " . date(DATE_W3C) . "\n"); fwrite($f, " * Source: " . $windowsZonesUrl . "\n"); fwrite($f, " *\n"); -fwrite($f, " * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).\n"); +fwrite($f, " * @copyright Copyright (C) fruux GmbH (https://fruux.com/).\n"); fwrite($f, " * @license http://sabre.io/license/ Modified BSD License\n"); fwrite($f, " */\n"); fwrite($f, "\n"); diff --git a/vendor/sabre/vobject/composer.json b/vendor/sabre/vobject/composer.json index bd6348a82..cfa4a712d 100644 --- a/vendor/sabre/vobject/composer.json +++ b/vendor/sabre/vobject/composer.json @@ -34,11 +34,11 @@ "require" : { "php" : ">=5.5", "ext-mbstring" : "*", - "sabre/xml" : "~1.1" + "sabre/xml" : ">=1.5 <3.0" }, "require-dev" : { "phpunit/phpunit" : "*", - "sabre/cs" : "~0.0.3" + "sabre/cs" : "^1.0.0" }, "suggest" : { diff --git a/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php b/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php index afa41ab1c..553912249 100644 --- a/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php +++ b/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php @@ -159,10 +159,10 @@ class BirthdayCalendarGenerator { // Create event. $event = $calendar->add('VEVENT', [ - 'SUMMARY' => sprintf($this->format, $object->FN->getValue()), - 'DTSTART' => new \DateTime($object->BDAY->getValue()), - 'RRULE' => 'FREQ=YEARLY', - 'TRANSP' => 'TRANSPARENT', + 'SUMMARY' => sprintf($this->format, $object->FN->getValue()), + 'DTSTART' => new \DateTime($object->BDAY->getValue()), + 'RRULE' => 'FREQ=YEARLY', + 'TRANSP' => 'TRANSPARENT', ]); // add VALUE=date diff --git a/vendor/sabre/vobject/lib/Component/VAlarm.php b/vendor/sabre/vobject/lib/Component/VAlarm.php index 8cbd572e6..faa8a5e74 100644 --- a/vendor/sabre/vobject/lib/Component/VAlarm.php +++ b/vendor/sabre/vobject/lib/Component/VAlarm.php @@ -2,10 +2,10 @@ namespace Sabre\VObject\Component; +use DateTimeImmutable; +use DateTimeInterface; use Sabre\VObject; use Sabre\VObject\InvalidDataException; -use DateTimeInterface; -use DateTimeImmutable; /** * VAlarm component. diff --git a/vendor/sabre/vobject/lib/Component/VCalendar.php b/vendor/sabre/vobject/lib/Component/VCalendar.php index 988db9dc2..1b3137d38 100644 --- a/vendor/sabre/vobject/lib/Component/VCalendar.php +++ b/vendor/sabre/vobject/lib/Component/VCalendar.php @@ -6,10 +6,10 @@ use DateTimeInterface; use DateTimeZone; use Sabre\VObject; use Sabre\VObject\Component; +use Sabre\VObject\InvalidDataException; use Sabre\VObject\Property; use Sabre\VObject\Recur\EventIterator; use Sabre\VObject\Recur\NoInstancesException; -use Sabre\VObject\InvalidDataException; /** * The VCalendar component. @@ -54,21 +54,21 @@ class VCalendar extends VObject\Document { * @var array */ static $valueMap = [ - 'BINARY' => 'Sabre\\VObject\\Property\\Binary', - 'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean', - 'CAL-ADDRESS' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress', - 'DATE' => 'Sabre\\VObject\\Property\\ICalendar\\Date', - 'DATE-TIME' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', - 'FLOAT' => 'Sabre\\VObject\\Property\\FloatValue', - 'INTEGER' => 'Sabre\\VObject\\Property\\IntegerValue', - 'PERIOD' => 'Sabre\\VObject\\Property\\ICalendar\\Period', - 'RECUR' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', - 'TEXT' => 'Sabre\\VObject\\Property\\Text', - 'TIME' => 'Sabre\\VObject\\Property\\Time', - 'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only. - 'URI' => 'Sabre\\VObject\\Property\\Uri', - 'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset', + 'BINARY' => 'Sabre\\VObject\\Property\\Binary', + 'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean', + 'CAL-ADDRESS' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress', + 'DATE' => 'Sabre\\VObject\\Property\\ICalendar\\Date', + 'DATE-TIME' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', + 'FLOAT' => 'Sabre\\VObject\\Property\\FloatValue', + 'INTEGER' => 'Sabre\\VObject\\Property\\IntegerValue', + 'PERIOD' => 'Sabre\\VObject\\Property\\ICalendar\\Period', + 'RECUR' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', + 'TEXT' => 'Sabre\\VObject\\Property\\Text', + 'TIME' => 'Sabre\\VObject\\Property\\Time', + 'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only. + 'URI' => 'Sabre\\VObject\\Property\\Uri', + 'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset', ]; /** @@ -78,40 +78,40 @@ class VCalendar extends VObject\Document { */ static $propertyMap = [ // Calendar properties - 'CALSCALE' => 'Sabre\\VObject\\Property\\FlatText', - 'METHOD' => 'Sabre\\VObject\\Property\\FlatText', - 'PRODID' => 'Sabre\\VObject\\Property\\FlatText', - 'VERSION' => 'Sabre\\VObject\\Property\\FlatText', + 'CALSCALE' => 'Sabre\\VObject\\Property\\FlatText', + 'METHOD' => 'Sabre\\VObject\\Property\\FlatText', + 'PRODID' => 'Sabre\\VObject\\Property\\FlatText', + 'VERSION' => 'Sabre\\VObject\\Property\\FlatText', // Component properties - 'ATTACH' => 'Sabre\\VObject\\Property\\Uri', - 'CATEGORIES' => 'Sabre\\VObject\\Property\\Text', - 'CLASS' => 'Sabre\\VObject\\Property\\FlatText', - 'COMMENT' => 'Sabre\\VObject\\Property\\FlatText', - 'DESCRIPTION' => 'Sabre\\VObject\\Property\\FlatText', - 'GEO' => 'Sabre\\VObject\\Property\\FloatValue', - 'LOCATION' => 'Sabre\\VObject\\Property\\FlatText', - 'PERCENT-COMPLETE' => 'Sabre\\VObject\\Property\\IntegerValue', - 'PRIORITY' => 'Sabre\\VObject\\Property\\IntegerValue', - 'RESOURCES' => 'Sabre\\VObject\\Property\\Text', - 'STATUS' => 'Sabre\\VObject\\Property\\FlatText', - 'SUMMARY' => 'Sabre\\VObject\\Property\\FlatText', + 'ATTACH' => 'Sabre\\VObject\\Property\\Uri', + 'CATEGORIES' => 'Sabre\\VObject\\Property\\Text', + 'CLASS' => 'Sabre\\VObject\\Property\\FlatText', + 'COMMENT' => 'Sabre\\VObject\\Property\\FlatText', + 'DESCRIPTION' => 'Sabre\\VObject\\Property\\FlatText', + 'GEO' => 'Sabre\\VObject\\Property\\FloatValue', + 'LOCATION' => 'Sabre\\VObject\\Property\\FlatText', + 'PERCENT-COMPLETE' => 'Sabre\\VObject\\Property\\IntegerValue', + 'PRIORITY' => 'Sabre\\VObject\\Property\\IntegerValue', + 'RESOURCES' => 'Sabre\\VObject\\Property\\Text', + 'STATUS' => 'Sabre\\VObject\\Property\\FlatText', + 'SUMMARY' => 'Sabre\\VObject\\Property\\FlatText', // Date and Time Component Properties - 'COMPLETED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'DTEND' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'DUE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'DTSTART' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', - 'FREEBUSY' => 'Sabre\\VObject\\Property\\ICalendar\\Period', - 'TRANSP' => 'Sabre\\VObject\\Property\\FlatText', + 'COMPLETED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'DTEND' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'DUE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'DTSTART' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', + 'FREEBUSY' => 'Sabre\\VObject\\Property\\ICalendar\\Period', + 'TRANSP' => 'Sabre\\VObject\\Property\\FlatText', // Time Zone Component Properties - 'TZID' => 'Sabre\\VObject\\Property\\FlatText', - 'TZNAME' => 'Sabre\\VObject\\Property\\FlatText', - 'TZOFFSETFROM' => 'Sabre\\VObject\\Property\\UtcOffset', - 'TZOFFSETTO' => 'Sabre\\VObject\\Property\\UtcOffset', - 'TZURL' => 'Sabre\\VObject\\Property\\Uri', + 'TZID' => 'Sabre\\VObject\\Property\\FlatText', + 'TZNAME' => 'Sabre\\VObject\\Property\\FlatText', + 'TZOFFSETFROM' => 'Sabre\\VObject\\Property\\UtcOffset', + 'TZOFFSETTO' => 'Sabre\\VObject\\Property\\UtcOffset', + 'TZURL' => 'Sabre\\VObject\\Property\\Uri', // Relationship Component Properties 'ATTENDEE' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress', @@ -123,15 +123,15 @@ class VCalendar extends VObject\Document { 'UID' => 'Sabre\\VObject\\Property\\FlatText', // Recurrence Component Properties - 'EXDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'RDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'RRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', - 'EXRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545 + 'EXDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'RDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'RRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', + 'EXRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545 // Alarm Component Properties - 'ACTION' => 'Sabre\\VObject\\Property\\FlatText', - 'REPEAT' => 'Sabre\\VObject\\Property\\IntegerValue', - 'TRIGGER' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', + 'ACTION' => 'Sabre\\VObject\\Property\\FlatText', + 'REPEAT' => 'Sabre\\VObject\\Property\\IntegerValue', + 'TRIGGER' => 'Sabre\\VObject\\Property\\ICalendar\\Duration', // Change Management Component Properties 'CREATED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', @@ -143,13 +143,13 @@ class VCalendar extends VObject\Document { 'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text', // Additions from draft-daboo-valarm-extensions-04 - 'ALARM-AGENT' => 'Sabre\\VObject\\Property\\Text', - 'ACKNOWLEDGED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', - 'PROXIMITY' => 'Sabre\\VObject\\Property\\Text', - 'DEFAULT-ALARM' => 'Sabre\\VObject\\Property\\Boolean', + 'ALARM-AGENT' => 'Sabre\\VObject\\Property\\Text', + 'ACKNOWLEDGED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime', + 'PROXIMITY' => 'Sabre\\VObject\\Property\\Text', + 'DEFAULT-ALARM' => 'Sabre\\VObject\\Property\\Boolean', // Additions from draft-daboo-calendar-availability-05 - 'BUSYTYPE' => 'Sabre\\VObject\\Property\\Text', + 'BUSYTYPE' => 'Sabre\\VObject\\Property\\Text', ]; diff --git a/vendor/sabre/vobject/lib/Component/VCard.php b/vendor/sabre/vobject/lib/Component/VCard.php index 3c05191a9..4f620de10 100644 --- a/vendor/sabre/vobject/lib/Component/VCard.php +++ b/vendor/sabre/vobject/lib/Component/VCard.php @@ -74,19 +74,19 @@ class VCard extends VObject\Document { static $propertyMap = [ // vCard 2.1 properties and up - 'N' => 'Sabre\\VObject\\Property\\Text', - 'FN' => 'Sabre\\VObject\\Property\\FlatText', - 'PHOTO' => 'Sabre\\VObject\\Property\\Binary', - 'BDAY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', - 'ADR' => 'Sabre\\VObject\\Property\\Text', - 'LABEL' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0 - 'TEL' => 'Sabre\\VObject\\Property\\FlatText', - 'EMAIL' => 'Sabre\\VObject\\Property\\FlatText', - 'MAILER' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0 - 'GEO' => 'Sabre\\VObject\\Property\\FlatText', - 'TITLE' => 'Sabre\\VObject\\Property\\FlatText', - 'ROLE' => 'Sabre\\VObject\\Property\\FlatText', - 'LOGO' => 'Sabre\\VObject\\Property\\Binary', + 'N' => 'Sabre\\VObject\\Property\\Text', + 'FN' => 'Sabre\\VObject\\Property\\FlatText', + 'PHOTO' => 'Sabre\\VObject\\Property\\Binary', + 'BDAY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', + 'ADR' => 'Sabre\\VObject\\Property\\Text', + 'LABEL' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0 + 'TEL' => 'Sabre\\VObject\\Property\\FlatText', + 'EMAIL' => 'Sabre\\VObject\\Property\\FlatText', + 'MAILER' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0 + 'GEO' => 'Sabre\\VObject\\Property\\FlatText', + 'TITLE' => 'Sabre\\VObject\\Property\\FlatText', + 'ROLE' => 'Sabre\\VObject\\Property\\FlatText', + 'LOGO' => 'Sabre\\VObject\\Property\\Binary', // 'AGENT' => 'Sabre\\VObject\\Property\\', // Todo: is an embedded vCard. Probably rare, so // not supported at the moment 'ORG' => 'Sabre\\VObject\\Property\\Text', @@ -107,13 +107,13 @@ class VCard extends VObject\Document { 'CLASS' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0 // rfc2739 properties - 'FBURL' => 'Sabre\\VObject\\Property\\Uri', - 'CAPURI' => 'Sabre\\VObject\\Property\\Uri', - 'CALURI' => 'Sabre\\VObject\\Property\\Uri', - 'CALADRURI' => 'Sabre\\VObject\\Property\\Uri', + 'FBURL' => 'Sabre\\VObject\\Property\\Uri', + 'CAPURI' => 'Sabre\\VObject\\Property\\Uri', + 'CALURI' => 'Sabre\\VObject\\Property\\Uri', + 'CALADRURI' => 'Sabre\\VObject\\Property\\Uri', // rfc4770 properties - 'IMPP' => 'Sabre\\VObject\\Property\\Uri', + 'IMPP' => 'Sabre\\VObject\\Property\\Uri', // vCard 4.0 properties 'SOURCE' => 'Sabre\\VObject\\Property\\Uri', @@ -127,9 +127,9 @@ class VCard extends VObject\Document { 'RELATED' => 'Sabre\\VObject\\Property\\Uri', // rfc6474 properties - 'BIRTHPLACE' => 'Sabre\\VObject\\Property\\FlatText', - 'DEATHPLACE' => 'Sabre\\VObject\\Property\\FlatText', - 'DEATHDATE' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', + 'BIRTHPLACE' => 'Sabre\\VObject\\Property\\FlatText', + 'DEATHPLACE' => 'Sabre\\VObject\\Property\\FlatText', + 'DEATHDATE' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // rfc6715 properties 'EXPERTISE' => 'Sabre\\VObject\\Property\\FlatText', @@ -368,7 +368,7 @@ class VCard extends VObject\Document { // FN is commented out, because it's already handled by the // validate function, which may also try to repair it. // 'FN' => '+', - 'UID' => '?', + 'UID' => '?', ]; } diff --git a/vendor/sabre/vobject/lib/DateTimeParser.php b/vendor/sabre/vobject/lib/DateTimeParser.php index 443bbb660..f9a802d25 100644 --- a/vendor/sabre/vobject/lib/DateTimeParser.php +++ b/vendor/sabre/vobject/lib/DateTimeParser.php @@ -2,9 +2,9 @@ namespace Sabre\VObject; +use DateInterval; use DateTimeImmutable; use DateTimeZone; -use DateInterval; /** * DateTimeParser. @@ -509,7 +509,7 @@ class DateTimeParser { static function parseVCardDateAndOrTime($date) { // \d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d - $valueDate = '/^(?J)(?:' . + $valueDate = '/^(?J)(?:' . '(?<year>\d{4})(?<month>\d\d)(?<date>\d\d)' . '|(?<year>\d{4})-(?<month>\d\d)' . '|--(?<month>\d\d)(?<date>\d\d)?' . @@ -517,7 +517,7 @@ class DateTimeParser { ')$/'; // (\d\d(\d\d(\d\d)?)?|-\d\d(\d\d)?|--\d\d)(Z|[+\-]\d\d(\d\d)?)? - $valueTime = '/^(?J)(?:' . + $valueTime = '/^(?J)(?:' . '((?<hour>\d\d)((?<minute>\d\d)(?<second>\d\d)?)?' . '|-(?<minute>\d\d)(?<second>\d\d)?' . '|--(?<second>\d\d))' . @@ -554,12 +554,12 @@ class DateTimeParser { ]; // The $valueDateTime expression has a bug with (?J) so we simulate it. - $parts['date0'] = &$parts['date']; - $parts['date1'] = &$parts['date']; - $parts['date2'] = &$parts['date']; + $parts['date0'] = &$parts['date']; + $parts['date1'] = &$parts['date']; + $parts['date2'] = &$parts['date']; $parts['month0'] = &$parts['month']; $parts['month1'] = &$parts['month']; - $parts['year0'] = &$parts['year']; + $parts['year0'] = &$parts['year']; foreach ($parts as $part => &$value) { if (!empty($matches[$part])) { diff --git a/vendor/sabre/vobject/lib/FreeBusyGenerator.php b/vendor/sabre/vobject/lib/FreeBusyGenerator.php index e33621090..e30b136c4 100644 --- a/vendor/sabre/vobject/lib/FreeBusyGenerator.php +++ b/vendor/sabre/vobject/lib/FreeBusyGenerator.php @@ -2,8 +2,8 @@ namespace Sabre\VObject; -use DateTimeInterface; use DateTimeImmutable; +use DateTimeInterface; use DateTimeZone; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Recur\EventIterator; @@ -152,7 +152,7 @@ class FreeBusyGenerator { $this->objects = []; foreach ($objects as $object) { - if (is_string($object)) { + if (is_string($object) || is_resource($object)) { $this->objects[] = Reader::read($object); } elseif ($object instanceof Component) { $this->objects[] = $object; @@ -292,7 +292,7 @@ class FreeBusyGenerator { list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd(); if ( (is_null($higherStart) || $higherStart < $compStart) && - (is_null($higherEnd) || $higherEnd > $compEnd) + (is_null($higherEnd) || $higherEnd > $compEnd) ) { // Component is fully covered by a higher priority diff --git a/vendor/sabre/vobject/lib/Parameter.php b/vendor/sabre/vobject/lib/Parameter.php index 270643eab..a99a33eec 100644 --- a/vendor/sabre/vobject/lib/Parameter.php +++ b/vendor/sabre/vobject/lib/Parameter.php @@ -2,8 +2,8 @@ namespace Sabre\VObject; -use Sabre\Xml; use ArrayIterator; +use Sabre\Xml; /** * VObject Parameter. diff --git a/vendor/sabre/vobject/lib/Parser/Json.php b/vendor/sabre/vobject/lib/Parser/Json.php index 370c981a8..a77258a2e 100644 --- a/vendor/sabre/vobject/lib/Parser/Json.php +++ b/vendor/sabre/vobject/lib/Parser/Json.php @@ -4,8 +4,8 @@ namespace Sabre\VObject\Parser; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Component\VCard; -use Sabre\VObject\ParseException; use Sabre\VObject\EofException; +use Sabre\VObject\ParseException; /** * Json Parser. diff --git a/vendor/sabre/vobject/lib/Parser/MimeDir.php b/vendor/sabre/vobject/lib/Parser/MimeDir.php index 6a7f9317b..fa75a1a3b 100644 --- a/vendor/sabre/vobject/lib/Parser/MimeDir.php +++ b/vendor/sabre/vobject/lib/Parser/MimeDir.php @@ -2,12 +2,12 @@ namespace Sabre\VObject\Parser; -use Sabre\VObject\ParseException; -use Sabre\VObject\EofException; use Sabre\VObject\Component; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Component\VCard; use Sabre\VObject\Document; +use Sabre\VObject\EofException; +use Sabre\VObject\ParseException; /** * MimeDir parser. diff --git a/vendor/sabre/vobject/lib/Parser/XML.php b/vendor/sabre/vobject/lib/Parser/XML.php index 060a7fe2e..5ac423984 100644 --- a/vendor/sabre/vobject/lib/Parser/XML.php +++ b/vendor/sabre/vobject/lib/Parser/XML.php @@ -20,7 +20,7 @@ use Sabre\Xml as SabreXml; */ class XML extends Parser { - const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0'; + const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0'; const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0'; /** @@ -100,7 +100,7 @@ class XML extends Parser { foreach ($this->input['value'] as &$vCard) { $this->root = new VCard(['version' => '4.0'], false); - $this->pointer = &$vCard; + $this->pointer = &$vCard; $this->parseVCardComponents($this->root); // We just parse the first <vcard /> element. @@ -172,10 +172,10 @@ class XML extends Parser { list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']); - $propertyName = $tagName; - $propertyValue = []; + $propertyName = $tagName; + $propertyValue = []; $propertyParameters = []; - $propertyType = 'text'; + $propertyType = 'text'; // A property which is not part of the standard. if ($namespace !== self::XCAL_NAMESPACE @@ -253,8 +253,8 @@ class XML extends Parser { switch ($propertyNameExtended) { case 'xcal:geo': - $propertyType = 'float'; - $propertyValue['latitude'] = 0; + $propertyType = 'float'; + $propertyValue['latitude'] = 0; $propertyValue['longitude'] = 0; foreach ($xmlProperty['value'] as $xmlRequestChild) { @@ -296,7 +296,7 @@ class XML extends Parser { if ('period' === $tagName) { $propertyParameters['value'] = 'PERIOD'; - $propertyValue[] = implode('/', $specialChild['value']); + $propertyValue[] = implode('/', $specialChild['value']); } else { @@ -306,7 +306,7 @@ class XML extends Parser { break; default: - $propertyType = static::getTagName($xmlProperty['value'][0]['name']); + $propertyType = static::getTagName($xmlProperty['value'][0]['name']); foreach ($xmlProperty['value'] as $value) { $propertyValue[] = $value['value']; @@ -343,7 +343,7 @@ class XML extends Parser { foreach ($components as $component) { - $componentName = static::getTagName($component['name']); + $componentName = static::getTagName($component['name']); $currentComponent = $this->root->createComponent( $componentName, null, @@ -404,7 +404,7 @@ class XML extends Parser { $reader->elementMap['{' . self::XCAL_NAMESPACE . '}recur'] = 'Sabre\VObject\Parser\XML\Element\KeyValue'; $reader->xml($input); - $input = $reader->parse(); + $input = $reader->parse(); } diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php b/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php index 66d366960..7b7e1ce8e 100644 --- a/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php +++ b/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php @@ -2,8 +2,8 @@ namespace Sabre\VObject\Property\ICalendar; -use Sabre\VObject\Property; use Sabre\VObject\DateTimeParser; +use Sabre\VObject\Property; /** * Duration property. diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Period.php b/vendor/sabre/vobject/lib/Property/ICalendar/Period.php index a4561d929..d35b425aa 100644 --- a/vendor/sabre/vobject/lib/Property/ICalendar/Period.php +++ b/vendor/sabre/vobject/lib/Property/ICalendar/Period.php @@ -2,8 +2,8 @@ namespace Sabre\VObject\Property\ICalendar; -use Sabre\VObject\Property; use Sabre\VObject\DateTimeParser; +use Sabre\VObject\Property; use Sabre\Xml; /** diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php b/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php index 8392a5cc1..434b77088 100644 --- a/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php +++ b/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php @@ -287,6 +287,54 @@ class Recur extends Property { } } } + // if there is no valid entry left, remove the whole value + if (is_array($value) && empty($values[$key])) { + unset($values[$key]); + } + } elseif ($key == 'BYWEEKNO') { + $byWeekNo = (array)$value; + foreach ($byWeekNo as $i => $v) { + if (!is_numeric($v) || (int)$v < -53 || (int)$v == 0 || (int)$v > 53) { + $warnings[] = [ + 'level' => $repair ? 1 : 3, + 'message' => 'BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', + 'node' => $this + ]; + if ($repair) { + if (is_array($value)) { + unset($values[$key][$i]); + } else { + unset($values[$key]); + } + } + } + } + // if there is no valid entry left, remove the whole value + if (is_array($value) && empty($values[$key])) { + unset($values[$key]); + } + } elseif ($key == 'BYYEARDAY') { + $byYearDay = (array)$value; + foreach ($byYearDay as $i => $v) { + if (!is_numeric($v) || (int)$v < -366 || (int)$v == 0 || (int)$v > 366) { + $warnings[] = [ + 'level' => $repair ? 1 : 3, + 'message' => 'BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', + 'node' => $this + ]; + if ($repair) { + if (is_array($value)) { + unset($values[$key][$i]); + } else { + unset($values[$key]); + } + } + } + } + // if there is no valid entry left, remove the whole value + if (is_array($value) && empty($values[$key])) { + unset($values[$key]); + } } } diff --git a/vendor/sabre/vobject/lib/Property/Text.php b/vendor/sabre/vobject/lib/Property/Text.php index abc17563f..476dcde4d 100644 --- a/vendor/sabre/vobject/lib/Property/Text.php +++ b/vendor/sabre/vobject/lib/Property/Text.php @@ -2,10 +2,10 @@ namespace Sabre\VObject\Property; -use Sabre\VObject\Property; use Sabre\VObject\Component; -use Sabre\VObject\Parser\MimeDir; use Sabre\VObject\Document; +use Sabre\VObject\Parser\MimeDir; +use Sabre\VObject\Property; use Sabre\Xml; /** diff --git a/vendor/sabre/vobject/lib/Property/Uri.php b/vendor/sabre/vobject/lib/Property/Uri.php index 58e676e60..88fcfaab8 100644 --- a/vendor/sabre/vobject/lib/Property/Uri.php +++ b/vendor/sabre/vobject/lib/Property/Uri.php @@ -2,8 +2,8 @@ namespace Sabre\VObject\Property; -use Sabre\VObject\Property; use Sabre\VObject\Parameter; +use Sabre\VObject\Property; /** * URI property. diff --git a/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php b/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php index 650e19cbf..3b4ae3bb5 100644 --- a/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php +++ b/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php @@ -2,9 +2,9 @@ namespace Sabre\VObject\Property\VCard; -use DateTimeInterface; -use DateTimeImmutable; use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use Sabre\VObject\DateTimeParser; use Sabre\VObject\InvalidDataException; use Sabre\VObject\Property; @@ -45,7 +45,7 @@ class DateAndOrTime extends Property { /** * Sets a multi-valued property. * - * You may also specify DateTime objects here. + * You may also specify DateTimeInterface objects here. * * @param array $parts * @@ -56,7 +56,7 @@ class DateAndOrTime extends Property { if (count($parts) > 1) { throw new \InvalidArgumentException('Only one value allowed'); } - if (isset($parts[0]) && $parts[0] instanceof \DateTime) { + if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) { $this->setDateTime($parts[0]); } else { parent::setParts($parts); @@ -69,15 +69,15 @@ class DateAndOrTime extends Property { * * This may be either a single, or multiple strings in an array. * - * Instead of strings, you may also use DateTime here. + * Instead of strings, you may also use DateTimeInterface here. * - * @param string|array|\DateTime $value + * @param string|array|DateTimeInterface $value * * @return void */ function setValue($value) { - if ($value instanceof \DateTime) { + if ($value instanceof DateTimeInterface) { $this->setDateTime($value); } else { parent::setValue($value); @@ -261,8 +261,8 @@ class DateAndOrTime extends Property { protected function xmlSerializeValue(Xml\Writer $writer) { $valueType = strtolower($this->getValueType()); - $parts = DateTimeParser::parseVCardDateAndOrTime($this->getValue()); - $value = ''; + $parts = DateTimeParser::parseVCardDateAndOrTime($this->getValue()); + $value = ''; // $d = defined $d = function($part) use ($parts) { @@ -280,7 +280,7 @@ class DateAndOrTime extends Property { // value-date = element date { // xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" } // } - if (($d('year') || $d('month') || $d('date')) + if (($d('year') || $d('month') || $d('date')) && (!$d('hour') && !$d('minute') && !$d('second') && !$d('timezone'))) { if ($d('year') && $d('month') && $d('date')) { @@ -298,8 +298,8 @@ class DateAndOrTime extends Property { // xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)" // ~ "(Z|[+\-]\d\d(\d\d)?)?" } // } - } elseif ((!$d('year') && !$d('month') && !$d('date')) - && ($d('hour') || $d('minute') || $d('second'))) { + } elseif ((!$d('year') && !$d('month') && !$d('date')) + && ($d('hour') || $d('minute') || $d('second'))) { if ($d('hour')) { $value .= $r('hour') . $r('minute') . $r('second'); diff --git a/vendor/sabre/vobject/lib/Recur/EventIterator.php b/vendor/sabre/vobject/lib/Recur/EventIterator.php index f91c336bc..d313305a0 100644 --- a/vendor/sabre/vobject/lib/Recur/EventIterator.php +++ b/vendor/sabre/vobject/lib/Recur/EventIterator.php @@ -2,9 +2,9 @@ namespace Sabre\VObject\Recur; -use DateTimeZone; use DateTimeImmutable; use DateTimeInterface; +use DateTimeZone; use InvalidArgumentException; use Sabre\VObject\Component; use Sabre\VObject\Component\VEvent; @@ -43,6 +43,8 @@ use Sabre\VObject\Settings; * * BYSETPOS * * FREQ=YEARLY * * BYMONTH + * * BYYEARDAY + * * BYWEEKNO * * BYMONTHDAY (only if BYMONTH is also set) * * BYDAY (only if BYMONTH is also set) * @@ -407,7 +409,7 @@ class EventIterator implements \Iterator { */ function fastForward(DateTimeInterface $dateTime) { - while ($this->valid() && $this->getDtEnd() < $dateTime) { + while ($this->valid() && $this->getDtEnd() <= $dateTime) { $this->next(); } diff --git a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php index 4c89f3ce4..20f34ef42 100644 --- a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php +++ b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php @@ -2,8 +2,8 @@ namespace Sabre\VObject\Recur; -use DateTimeInterface; use DateTimeImmutable; +use DateTimeInterface; use Iterator; use Sabre\VObject\DateTimeParser; use Sabre\VObject\InvalidDataException; @@ -374,8 +374,8 @@ class RRuleIterator implements Iterator { $currentHour = $this->currentDate->format('G'); } while ( - ($this->byDay && !in_array($currentDay, $recurrenceDays)) || - ($this->byHour && !in_array($currentHour, $recurrenceHours)) || + ($this->byDay && !in_array($currentDay, $recurrenceDays)) || + ($this->byHour && !in_array($currentHour, $recurrenceHours)) || ($this->byMonth && !in_array($currentMonth, $recurrenceMonths)) ); @@ -537,6 +537,83 @@ class RRuleIterator implements Iterator { } + if ($this->byWeekNo !== null) { // byWeekNo is an array with values from -53 to -1, or 1 to 53 + $dayOffsets = []; + if ($this->byDay) { + foreach ($this->byDay as $byDay) { + $dayOffsets[] = $this->dayMap[$byDay]; + } + } else { // default is Monday + $dayOffsets[] = 1; + } + + $currentYear = $this->currentDate->format('Y'); + + while (true) { + $checkDates = []; + + // loop through all WeekNo and Days to check all the combinations + foreach ($this->byWeekNo as $byWeekNo) { + foreach ($dayOffsets as $dayOffset) { + $date = clone $this->currentDate; + $date->setISODate($currentYear, $byWeekNo, $dayOffset); + + if ($date > $this->currentDate) { + $checkDates[] = $date; + } + } + } + + if (count($checkDates) > 0) { + $this->currentDate = min($checkDates); + return; + } + + // if there is no date found, check the next year + $currentYear += $this->interval; + } + } + + if ($this->byYearDay !== null) { // byYearDay is an array with values from -366 to -1, or 1 to 366 + $dayOffsets = []; + if ($this->byDay) { + foreach ($this->byDay as $byDay) { + $dayOffsets[] = $this->dayMap[$byDay]; + } + } else { // default is Monday-Sunday + $dayOffsets = [1,2,3,4,5,6,7]; + } + + $currentYear = $this->currentDate->format('Y'); + + while (true) { + $checkDates = []; + + // loop through all YearDay and Days to check all the combinations + foreach ($this->byYearDay as $byYearDay) { + $date = clone $this->currentDate; + $date->setDate($currentYear, 1, 1); + if ($byYearDay > 0) { + $date->add(new \DateInterval('P' . $byYearDay . 'D')); + } else { + $date->sub(new \DateInterval('P' . abs($byYearDay) . 'D')); + } + + if ($date > $this->currentDate && in_array($date->format('N'), $dayOffsets)) { + $checkDates[] = $date; + } + } + + if (count($checkDates) > 0) { + $this->currentDate = min($checkDates); + return; + } + + // if there is no date found, check the next year + $currentYear += $this->interval; + } + } + // The easiest form $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' years'); return; @@ -710,10 +787,20 @@ class RRuleIterator implements Iterator { case 'BYYEARDAY' : $this->byYearDay = (array)$value; + foreach ($this->byYearDay as $byYearDay) { + if (!is_numeric($byYearDay) || (int)$byYearDay < -366 || (int)$byYearDay == 0 || (int)$byYearDay > 366) { + throw new InvalidDataException('BYYEARDAY in RRULE must have value(s) from 1 to 366, or -366 to -1!'); + } + } break; case 'BYWEEKNO' : $this->byWeekNo = (array)$value; + foreach ($this->byWeekNo as $byWeekNo) { + if (!is_numeric($byWeekNo) || (int)$byWeekNo < -53 || (int)$byWeekNo == 0 || (int)$byWeekNo > 53) { + throw new InvalidDataException('BYWEEKNO in RRULE must have value(s) from 1 to 53, or -53 to -1!'); + } + } break; case 'BYMONTH' : diff --git a/vendor/sabre/vobject/lib/TimeZoneUtil.php b/vendor/sabre/vobject/lib/TimeZoneUtil.php index 2a95ae898..925183e8d 100644 --- a/vendor/sabre/vobject/lib/TimeZoneUtil.php +++ b/vendor/sabre/vobject/lib/TimeZoneUtil.php @@ -165,6 +165,16 @@ class TimeZoneUtil { return new \DateTimeZone(self::$map[$tzid]); } + // Some Microsoft products prefix the offset first, so let's strip that off + // and see if it is our tzid map. We don't want to check for this first just + // in case there are overrides in our tzid map. + if (preg_match('/^\((UTC|GMT)(\+|\-)[\d]{2}\:[\d]{2}\) (.*)/', $tzid, $matches)) { + $tzidAlternate = $matches[3]; + if (isset(self::$map[$tzidAlternate])) { + return new \DateTimeZone(self::$map[$tzidAlternate]); + } + } + // Maybe the author was hyper-lazy and just included an offset. We // support it, but we aren't happy about it. if (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) { diff --git a/vendor/sabre/vobject/lib/Version.php b/vendor/sabre/vobject/lib/Version.php index ca9f21960..346e2044d 100644 --- a/vendor/sabre/vobject/lib/Version.php +++ b/vendor/sabre/vobject/lib/Version.php @@ -14,6 +14,6 @@ class Version { /** * Full version number. */ - const VERSION = '4.1.1'; + const VERSION = '4.1.2'; } diff --git a/vendor/sabre/vobject/lib/timezonedata/lotuszones.php b/vendor/sabre/vobject/lib/timezonedata/lotuszones.php index 7d0785f04..79d555a92 100644 --- a/vendor/sabre/vobject/lib/timezonedata/lotuszones.php +++ b/vendor/sabre/vobject/lib/timezonedata/lotuszones.php @@ -17,85 +17,85 @@ return [ 'Mexico Standard Time 2' => 'America/Chihuahua', 'Mountain' => 'America/Denver', // 'Mountain Standard Time' => 'America/Chihuahua', // conflict with windows timezones. - 'US Mountain' => 'America/Phoenix', - 'Canada Central' => 'America/Edmonton', - 'Central America' => 'America/Guatemala', - 'Central' => 'America/Chicago', + 'US Mountain' => 'America/Phoenix', + 'Canada Central' => 'America/Edmonton', + 'Central America' => 'America/Guatemala', + 'Central' => 'America/Chicago', // 'Central Standard Time' => 'America/Mexico_City', // conflict with windows timezones. - 'Mexico' => 'America/Mexico_City', - 'Eastern' => 'America/New_York', - 'SA Pacific' => 'America/Bogota', - 'US Eastern' => 'America/Indiana/Indianapolis', - 'Venezuela' => 'America/Caracas', - 'Atlantic' => 'America/Halifax', - 'Central Brazilian' => 'America/Manaus', - 'Pacific SA' => 'America/Santiago', - 'SA Western' => 'America/La_Paz', - 'Newfoundland' => 'America/St_Johns', - 'Argentina' => 'America/Argentina/Buenos_Aires', - 'E. South America' => 'America/Belem', - 'Greenland' => 'America/Godthab', - 'Montevideo' => 'America/Montevideo', - 'SA Eastern' => 'America/Belem', + 'Mexico' => 'America/Mexico_City', + 'Eastern' => 'America/New_York', + 'SA Pacific' => 'America/Bogota', + 'US Eastern' => 'America/Indiana/Indianapolis', + 'Venezuela' => 'America/Caracas', + 'Atlantic' => 'America/Halifax', + 'Central Brazilian' => 'America/Manaus', + 'Pacific SA' => 'America/Santiago', + 'SA Western' => 'America/La_Paz', + 'Newfoundland' => 'America/St_Johns', + 'Argentina' => 'America/Argentina/Buenos_Aires', + 'E. South America' => 'America/Belem', + 'Greenland' => 'America/Godthab', + 'Montevideo' => 'America/Montevideo', + 'SA Eastern' => 'America/Belem', // 'Mid-Atlantic' => 'Etc/GMT-2', // conflict with windows timezones. - 'Azores' => 'Atlantic/Azores', - 'Cape Verde' => 'Atlantic/Cape_Verde', - 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT. - 'Morocco' => 'Africa/Casablanca', - 'Central Europe' => 'Europe/Prague', - 'Central European' => 'Europe/Sarajevo', - 'Romance' => 'Europe/Paris', - 'W. Central Africa' => 'Africa/Lagos', // Best guess - 'W. Europe' => 'Europe/Amsterdam', - 'E. Europe' => 'Europe/Minsk', - 'Egypt' => 'Africa/Cairo', - 'FLE' => 'Europe/Helsinki', - 'GTB' => 'Europe/Athens', - 'Israel' => 'Asia/Jerusalem', - 'Jordan' => 'Asia/Amman', - 'Middle East' => 'Asia/Beirut', - 'Namibia' => 'Africa/Windhoek', - 'South Africa' => 'Africa/Harare', - 'Arab' => 'Asia/Kuwait', - 'Arabic' => 'Asia/Baghdad', - 'E. Africa' => 'Africa/Nairobi', - 'Georgian' => 'Asia/Tbilisi', - 'Russian' => 'Europe/Moscow', - 'Iran' => 'Asia/Tehran', - 'Arabian' => 'Asia/Muscat', - 'Armenian' => 'Asia/Yerevan', - 'Azerbijan' => 'Asia/Baku', - 'Caucasus' => 'Asia/Yerevan', - 'Mauritius' => 'Indian/Mauritius', - 'Afghanistan' => 'Asia/Kabul', - 'Ekaterinburg' => 'Asia/Yekaterinburg', - 'Pakistan' => 'Asia/Karachi', - 'West Asia' => 'Asia/Tashkent', - 'India' => 'Asia/Calcutta', - 'Sri Lanka' => 'Asia/Colombo', - 'Nepal' => 'Asia/Kathmandu', - 'Central Asia' => 'Asia/Dhaka', - 'N. Central Asia' => 'Asia/Almaty', - 'Myanmar' => 'Asia/Rangoon', - 'North Asia' => 'Asia/Krasnoyarsk', - 'SE Asia' => 'Asia/Bangkok', - 'China' => 'Asia/Shanghai', - 'North Asia East' => 'Asia/Irkutsk', - 'Singapore' => 'Asia/Singapore', - 'Taipei' => 'Asia/Taipei', - 'W. Australia' => 'Australia/Perth', - 'Korea' => 'Asia/Seoul', - 'Tokyo' => 'Asia/Tokyo', - 'Yakutsk' => 'Asia/Yakutsk', - 'AUS Central' => 'Australia/Darwin', - 'Cen. Australia' => 'Australia/Adelaide', - 'AUS Eastern' => 'Australia/Sydney', - 'E. Australia' => 'Australia/Brisbane', - 'Tasmania' => 'Australia/Hobart', - 'Vladivostok' => 'Asia/Vladivostok', - 'West Pacific' => 'Pacific/Guam', - 'Central Pacific' => 'Asia/Magadan', - 'Fiji' => 'Pacific/Fiji', - 'New Zealand' => 'Pacific/Auckland', - 'Tonga' => 'Pacific/Tongatapu', + 'Azores' => 'Atlantic/Azores', + 'Cape Verde' => 'Atlantic/Cape_Verde', + 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT. + 'Morocco' => 'Africa/Casablanca', + 'Central Europe' => 'Europe/Prague', + 'Central European' => 'Europe/Sarajevo', + 'Romance' => 'Europe/Paris', + 'W. Central Africa' => 'Africa/Lagos', // Best guess + 'W. Europe' => 'Europe/Amsterdam', + 'E. Europe' => 'Europe/Minsk', + 'Egypt' => 'Africa/Cairo', + 'FLE' => 'Europe/Helsinki', + 'GTB' => 'Europe/Athens', + 'Israel' => 'Asia/Jerusalem', + 'Jordan' => 'Asia/Amman', + 'Middle East' => 'Asia/Beirut', + 'Namibia' => 'Africa/Windhoek', + 'South Africa' => 'Africa/Harare', + 'Arab' => 'Asia/Kuwait', + 'Arabic' => 'Asia/Baghdad', + 'E. Africa' => 'Africa/Nairobi', + 'Georgian' => 'Asia/Tbilisi', + 'Russian' => 'Europe/Moscow', + 'Iran' => 'Asia/Tehran', + 'Arabian' => 'Asia/Muscat', + 'Armenian' => 'Asia/Yerevan', + 'Azerbijan' => 'Asia/Baku', + 'Caucasus' => 'Asia/Yerevan', + 'Mauritius' => 'Indian/Mauritius', + 'Afghanistan' => 'Asia/Kabul', + 'Ekaterinburg' => 'Asia/Yekaterinburg', + 'Pakistan' => 'Asia/Karachi', + 'West Asia' => 'Asia/Tashkent', + 'India' => 'Asia/Calcutta', + 'Sri Lanka' => 'Asia/Colombo', + 'Nepal' => 'Asia/Kathmandu', + 'Central Asia' => 'Asia/Dhaka', + 'N. Central Asia' => 'Asia/Almaty', + 'Myanmar' => 'Asia/Rangoon', + 'North Asia' => 'Asia/Krasnoyarsk', + 'SE Asia' => 'Asia/Bangkok', + 'China' => 'Asia/Shanghai', + 'North Asia East' => 'Asia/Irkutsk', + 'Singapore' => 'Asia/Singapore', + 'Taipei' => 'Asia/Taipei', + 'W. Australia' => 'Australia/Perth', + 'Korea' => 'Asia/Seoul', + 'Tokyo' => 'Asia/Tokyo', + 'Yakutsk' => 'Asia/Yakutsk', + 'AUS Central' => 'Australia/Darwin', + 'Cen. Australia' => 'Australia/Adelaide', + 'AUS Eastern' => 'Australia/Sydney', + 'E. Australia' => 'Australia/Brisbane', + 'Tasmania' => 'Australia/Hobart', + 'Vladivostok' => 'Asia/Vladivostok', + 'West Pacific' => 'Pacific/Guam', + 'Central Pacific' => 'Asia/Magadan', + 'Fiji' => 'Pacific/Fiji', + 'New Zealand' => 'Pacific/Auckland', + 'Tonga' => 'Pacific/Tongatapu', ]; diff --git a/vendor/sabre/vobject/lib/timezonedata/windowszones.php b/vendor/sabre/vobject/lib/timezonedata/windowszones.php index ac69847cc..29f3a6cb8 100644 --- a/vendor/sabre/vobject/lib/timezonedata/windowszones.php +++ b/vendor/sabre/vobject/lib/timezonedata/windowszones.php @@ -3,28 +3,33 @@ /** * Automatically generated timezone file * - * Last update: 2015-07-27T16:56:36-04:00 + * Last update: 2016-08-24T17:35:38-04:00 * Source: http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml * - * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/). * @license http://sabre.io/license/ Modified BSD License */ -return [ +return [ 'AUS Central Standard Time' => 'Australia/Darwin', 'AUS Eastern Standard Time' => 'Australia/Sydney', 'Afghanistan Standard Time' => 'Asia/Kabul', 'Alaskan Standard Time' => 'America/Anchorage', + 'Aleutian Standard Time' => 'America/Adak', + 'Altai Standard Time' => 'Asia/Barnaul', 'Arab Standard Time' => 'Asia/Riyadh', 'Arabian Standard Time' => 'Asia/Dubai', 'Arabic Standard Time' => 'Asia/Baghdad', 'Argentina Standard Time' => 'America/Buenos_Aires', + 'Astrakhan Standard Time' => 'Europe/Astrakhan', 'Atlantic Standard Time' => 'America/Halifax', + 'Aus Central W. Standard Time' => 'Australia/Eucla', 'Azerbaijan Standard Time' => 'Asia/Baku', 'Azores Standard Time' => 'Atlantic/Azores', 'Bahia Standard Time' => 'America/Bahia', 'Bangladesh Standard Time' => 'Asia/Dhaka', 'Belarus Standard Time' => 'Europe/Minsk', + 'Bougainville Standard Time' => 'Pacific/Bougainville', 'Canada Central Standard Time' => 'America/Regina', 'Cape Verde Standard Time' => 'Atlantic/Cape_Verde', 'Caucasus Standard Time' => 'Asia/Yerevan', @@ -37,11 +42,15 @@ return [ 'Central Pacific Standard Time' => 'Pacific/Guadalcanal', 'Central Standard Time' => 'America/Chicago', 'Central Standard Time (Mexico)' => 'America/Mexico_City', + 'Chatham Islands Standard Time' => 'Pacific/Chatham', 'China Standard Time' => 'Asia/Shanghai', + 'Cuba Standard Time' => 'America/Havana', 'Dateline Standard Time' => 'Etc/GMT+12', 'E. Africa Standard Time' => 'Africa/Nairobi', 'E. Australia Standard Time' => 'Australia/Brisbane', + 'E. Europe Standard Time' => 'Europe/Chisinau', 'E. South America Standard Time' => 'America/Sao_Paulo', + 'Easter Island Standard Time' => 'Pacific/Easter', 'Eastern Standard Time' => 'America/New_York', 'Eastern Standard Time (Mexico)' => 'America/Cancun', 'Egypt Standard Time' => 'Africa/Cairo', @@ -53,6 +62,7 @@ return [ 'Georgian Standard Time' => 'Asia/Tbilisi', 'Greenland Standard Time' => 'America/Godthab', 'Greenwich Standard Time' => 'Atlantic/Reykjavik', + 'Haiti Standard Time' => 'America/Port-au-Prince', 'Hawaiian Standard Time' => 'Pacific/Honolulu', 'India Standard Time' => 'Asia/Calcutta', 'Iran Standard Time' => 'Asia/Tehran', @@ -62,7 +72,9 @@ return [ 'Korea Standard Time' => 'Asia/Seoul', 'Libya Standard Time' => 'Africa/Tripoli', 'Line Islands Standard Time' => 'Pacific/Kiritimati', + 'Lord Howe Standard Time' => 'Australia/Lord_Howe', 'Magadan Standard Time' => 'Asia/Magadan', + 'Marquesas Standard Time' => 'Pacific/Marquesas', 'Mauritius Standard Time' => 'Indian/Mauritius', 'Middle East Standard Time' => 'Asia/Beirut', 'Montevideo Standard Time' => 'America/Montevideo', @@ -75,11 +87,13 @@ return [ 'Nepal Standard Time' => 'Asia/Katmandu', 'New Zealand Standard Time' => 'Pacific/Auckland', 'Newfoundland Standard Time' => 'America/St_Johns', + 'Norfolk Standard Time' => 'Pacific/Norfolk', 'North Asia East Standard Time' => 'Asia/Irkutsk', 'North Asia Standard Time' => 'Asia/Krasnoyarsk', + 'North Korea Standard Time' => 'Asia/Pyongyang', 'Pacific SA Standard Time' => 'America/Santiago', 'Pacific Standard Time' => 'America/Los_Angeles', - 'Pacific Standard Time (Mexico)' => 'America/Santa_Isabel', + 'Pacific Standard Time (Mexico)' => 'America/Tijuana', 'Pakistan Standard Time' => 'Asia/Karachi', 'Paraguay Standard Time' => 'America/Asuncion', 'Romance Standard Time' => 'Europe/Paris', @@ -91,6 +105,8 @@ return [ 'SA Pacific Standard Time' => 'America/Bogota', 'SA Western Standard Time' => 'America/La_Paz', 'SE Asia Standard Time' => 'Asia/Bangkok', + 'Saint Pierre Standard Time' => 'America/Miquelon', + 'Sakhalin Standard Time' => 'Asia/Sakhalin', 'Samoa Standard Time' => 'Pacific/Apia', 'Singapore Standard Time' => 'Asia/Singapore', 'South Africa Standard Time' => 'Africa/Johannesburg', @@ -98,14 +114,20 @@ return [ 'Syria Standard Time' => 'Asia/Damascus', 'Taipei Standard Time' => 'Asia/Taipei', 'Tasmania Standard Time' => 'Australia/Hobart', + 'Tocantins Standard Time' => 'America/Araguaina', 'Tokyo Standard Time' => 'Asia/Tokyo', + 'Tomsk Standard Time' => 'Asia/Tomsk', 'Tonga Standard Time' => 'Pacific/Tongatapu', + 'Transbaikal Standard Time' => 'Asia/Chita', 'Turkey Standard Time' => 'Europe/Istanbul', + 'Turks And Caicos Standard Time' => 'America/Grand_Turk', 'US Eastern Standard Time' => 'America/Indianapolis', 'US Mountain Standard Time' => 'America/Phoenix', 'UTC' => 'Etc/GMT', 'UTC+12' => 'Etc/GMT-12', 'UTC-02' => 'Etc/GMT+2', + 'UTC-08' => 'Etc/GMT+8', + 'UTC-09' => 'Etc/GMT+9', 'UTC-11' => 'Etc/GMT+11', 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar', 'Venezuela Standard Time' => 'America/Caracas', @@ -113,7 +135,9 @@ return [ 'W. Australia Standard Time' => 'Australia/Perth', 'W. Central Africa Standard Time' => 'Africa/Lagos', 'W. Europe Standard Time' => 'Europe/Berlin', + 'W. Mongolia Standard Time' => 'Asia/Hovd', 'West Asia Standard Time' => 'Asia/Tashkent', + 'West Bank Standard Time' => 'Asia/Hebron', 'West Pacific Standard Time' => 'Pacific/Port_Moresby', 'Yakutsk Standard Time' => 'Asia/Yakutsk', ]; |