From 6c641b1834539c65edb35dd43a6afa7620e73e1c Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 14 Mar 2017 09:09:05 +1100 Subject: move oauth2 to vendor --- composer.json | 3 +- composer.lock | 2851 +------------------- library/oauth2/.gitignore | 5 - library/oauth2/.travis.yml | 30 - library/oauth2/CHANGELOG.md | 152 -- library/oauth2/LICENSE | 21 - library/oauth2/README.md | 8 - library/oauth2/phpunit.xml | 25 - library/oauth2/src/OAuth2/Autoloader.php | 48 - .../ClientAssertionTypeInterface.php | 15 - .../src/OAuth2/ClientAssertionType/HttpBasic.php | 123 - .../src/OAuth2/Controller/AuthorizeController.php | 388 --- .../Controller/AuthorizeControllerInterface.php | 43 - .../src/OAuth2/Controller/ResourceController.php | 111 - .../Controller/ResourceControllerInterface.php | 26 - .../src/OAuth2/Controller/TokenController.php | 278 -- .../OAuth2/Controller/TokenControllerInterface.php | 32 - .../src/OAuth2/Encryption/EncryptionInterface.php | 11 - .../oauth2/src/OAuth2/Encryption/FirebaseJwt.php | 47 - library/oauth2/src/OAuth2/Encryption/Jwt.php | 173 -- .../src/OAuth2/GrantType/AuthorizationCode.php | 100 - .../src/OAuth2/GrantType/ClientCredentials.php | 67 - .../src/OAuth2/GrantType/GrantTypeInterface.php | 20 - library/oauth2/src/OAuth2/GrantType/JwtBearer.php | 226 -- .../oauth2/src/OAuth2/GrantType/RefreshToken.php | 111 - .../src/OAuth2/GrantType/UserCredentials.php | 83 - .../OpenID/Controller/AuthorizeController.php | 106 - .../Controller/AuthorizeControllerInterface.php | 10 - .../OpenID/Controller/UserInfoController.php | 58 - .../Controller/UserInfoControllerInterface.php | 23 - .../OAuth2/OpenID/GrantType/AuthorizationCode.php | 33 - .../OpenID/ResponseType/AuthorizationCode.php | 60 - .../ResponseType/AuthorizationCodeInterface.php | 27 - .../src/OAuth2/OpenID/ResponseType/CodeIdToken.php | 24 - .../OpenID/ResponseType/CodeIdTokenInterface.php | 9 - .../src/OAuth2/OpenID/ResponseType/IdToken.php | 124 - .../OpenID/ResponseType/IdTokenInterface.php | 29 - .../OAuth2/OpenID/ResponseType/IdTokenToken.php | 27 - .../OpenID/ResponseType/IdTokenTokenInterface.php | 9 - .../OpenID/Storage/AuthorizationCodeInterface.php | 37 - .../OAuth2/OpenID/Storage/UserClaimsInterface.php | 38 - library/oauth2/src/OAuth2/Request.php | 213 -- library/oauth2/src/OAuth2/RequestInterface.php | 16 - library/oauth2/src/OAuth2/Response.php | 369 --- library/oauth2/src/OAuth2/ResponseInterface.php | 24 - .../oauth2/src/OAuth2/ResponseType/AccessToken.php | 194 -- .../OAuth2/ResponseType/AccessTokenInterface.php | 34 - .../src/OAuth2/ResponseType/AuthorizationCode.php | 100 - .../ResponseType/AuthorizationCodeInterface.php | 30 - .../src/OAuth2/ResponseType/JwtAccessToken.php | 124 - .../OAuth2/ResponseType/ResponseTypeInterface.php | 8 - library/oauth2/src/OAuth2/Scope.php | 103 - library/oauth2/src/OAuth2/ScopeInterface.php | 40 - library/oauth2/src/OAuth2/Server.php | 832 ------ .../src/OAuth2/Storage/AccessTokenInterface.php | 64 - .../OAuth2/Storage/AuthorizationCodeInterface.php | 86 - library/oauth2/src/OAuth2/Storage/Cassandra.php | 480 ---- .../OAuth2/Storage/ClientCredentialsInterface.php | 49 - .../oauth2/src/OAuth2/Storage/ClientInterface.php | 66 - library/oauth2/src/OAuth2/Storage/CouchbaseDB.php | 331 --- library/oauth2/src/OAuth2/Storage/DynamoDB.php | 540 ---- .../oauth2/src/OAuth2/Storage/JwtAccessToken.php | 88 - .../src/OAuth2/Storage/JwtAccessTokenInterface.php | 14 - .../src/OAuth2/Storage/JwtBearerInterface.php | 74 - library/oauth2/src/OAuth2/Storage/Memory.php | 381 --- library/oauth2/src/OAuth2/Storage/Mongo.php | 339 --- library/oauth2/src/OAuth2/Storage/Pdo.php | 553 ---- .../src/OAuth2/Storage/PublicKeyInterface.php | 16 - library/oauth2/src/OAuth2/Storage/Redis.php | 321 --- .../src/OAuth2/Storage/RefreshTokenInterface.php | 82 - .../oauth2/src/OAuth2/Storage/ScopeInterface.php | 46 - .../OAuth2/Storage/UserCredentialsInterface.php | 52 - library/oauth2/src/OAuth2/TokenType/Bearer.php | 130 - library/oauth2/src/OAuth2/TokenType/Mac.php | 22 - .../src/OAuth2/TokenType/TokenTypeInterface.php | 21 - library/oauth2/test/OAuth2/AutoloadTest.php | 16 - .../OAuth2/Controller/AuthorizeControllerTest.php | 492 ---- .../OAuth2/Controller/ResourceControllerTest.php | 175 -- .../test/OAuth2/Controller/TokenControllerTest.php | 289 -- .../test/OAuth2/Encryption/FirebaseJwtTest.php | 102 - library/oauth2/test/OAuth2/Encryption/JwtTest.php | 102 - .../OAuth2/GrantType/AuthorizationCodeTest.php | 207 -- .../OAuth2/GrantType/ClientCredentialsTest.php | 159 -- .../oauth2/test/OAuth2/GrantType/ImplicitTest.php | 143 - .../oauth2/test/OAuth2/GrantType/JwtBearerTest.php | 360 --- .../test/OAuth2/GrantType/RefreshTokenTest.php | 204 -- .../test/OAuth2/GrantType/UserCredentialsTest.php | 172 -- .../OpenID/Controller/AuthorizeControllerTest.php | 182 -- .../OpenID/Controller/UserInfoControllerTest.php | 44 - .../OpenID/GrantType/AuthorizationCodeTest.php | 57 - .../OAuth2/OpenID/ResponseType/CodeIdTokenTest.php | 182 -- .../OAuth2/OpenID/ResponseType/IdTokenTest.php | 184 -- .../OpenID/ResponseType/IdTokenTokenTest.php | 91 - .../OpenID/Storage/AuthorizationCodeTest.php | 95 - .../test/OAuth2/OpenID/Storage/UserClaimsTest.php | 41 - library/oauth2/test/OAuth2/RequestTest.php | 98 - library/oauth2/test/OAuth2/ResponseTest.php | 17 - .../test/OAuth2/ResponseType/AccessTokenTest.php | 107 - .../OAuth2/ResponseType/JwtAccessTokenTest.php | 160 -- library/oauth2/test/OAuth2/ScopeTest.php | 42 - library/oauth2/test/OAuth2/ServerTest.php | 684 ----- .../oauth2/test/OAuth2/Storage/AccessTokenTest.php | 102 - .../test/OAuth2/Storage/AuthorizationCodeTest.php | 106 - .../test/OAuth2/Storage/ClientCredentialsTest.php | 28 - library/oauth2/test/OAuth2/Storage/ClientTest.php | 110 - .../oauth2/test/OAuth2/Storage/DynamoDBTest.php | 40 - .../test/OAuth2/Storage/JwtAccessTokenTest.php | 41 - .../oauth2/test/OAuth2/Storage/JwtBearerTest.php | 25 - library/oauth2/test/OAuth2/Storage/PdoTest.php | 39 - .../oauth2/test/OAuth2/Storage/PublicKeyTest.php | 29 - .../test/OAuth2/Storage/RefreshTokenTest.php | 41 - library/oauth2/test/OAuth2/Storage/ScopeTest.php | 53 - .../test/OAuth2/Storage/UserCredentialsTest.php | 40 - .../oauth2/test/OAuth2/TokenType/BearerTest.php | 58 - library/oauth2/test/bootstrap.php | 12 - library/oauth2/test/cleanup.php | 15 - library/oauth2/test/config/keys/id_rsa | 15 - library/oauth2/test/config/keys/id_rsa.pub | 16 - library/oauth2/test/config/storage.json | 181 -- .../oauth2/test/lib/OAuth2/Request/TestRequest.php | 61 - .../oauth2/test/lib/OAuth2/Storage/BaseTest.php | 34 - .../oauth2/test/lib/OAuth2/Storage/Bootstrap.php | 888 ------ .../oauth2/test/lib/OAuth2/Storage/NullStorage.php | 32 - vendor/autoload.php | 2 +- vendor/bshaffer/oauth2-server-php/CHANGELOG.md | 182 ++ vendor/bshaffer/oauth2-server-php/LICENSE | 21 + vendor/bshaffer/oauth2-server-php/README.md | 8 + vendor/bshaffer/oauth2-server-php/composer.json | 34 + .../oauth2-server-php/src/OAuth2/Autoloader.php | 48 + .../ClientAssertionTypeInterface.php | 15 + .../src/OAuth2/ClientAssertionType/HttpBasic.php | 123 + .../src/OAuth2/Controller/AuthorizeController.php | 393 +++ .../Controller/AuthorizeControllerInterface.php | 43 + .../src/OAuth2/Controller/ResourceController.php | 111 + .../Controller/ResourceControllerInterface.php | 26 + .../src/OAuth2/Controller/TokenController.php | 295 ++ .../OAuth2/Controller/TokenControllerInterface.php | 32 + .../src/OAuth2/Encryption/EncryptionInterface.php | 11 + .../src/OAuth2/Encryption/FirebaseJwt.php | 47 + .../src/OAuth2/Encryption/Jwt.php | 173 ++ .../src/OAuth2/GrantType/AuthorizationCode.php | 100 + .../src/OAuth2/GrantType/ClientCredentials.php | 67 + .../src/OAuth2/GrantType/GrantTypeInterface.php | 20 + .../src/OAuth2/GrantType/JwtBearer.php | 226 ++ .../src/OAuth2/GrantType/RefreshToken.php | 111 + .../src/OAuth2/GrantType/UserCredentials.php | 83 + .../OpenID/Controller/AuthorizeController.php | 106 + .../Controller/AuthorizeControllerInterface.php | 10 + .../OpenID/Controller/UserInfoController.php | 58 + .../Controller/UserInfoControllerInterface.php | 23 + .../OAuth2/OpenID/GrantType/AuthorizationCode.php | 33 + .../OpenID/ResponseType/AuthorizationCode.php | 60 + .../ResponseType/AuthorizationCodeInterface.php | 27 + .../src/OAuth2/OpenID/ResponseType/CodeIdToken.php | 24 + .../OpenID/ResponseType/CodeIdTokenInterface.php | 9 + .../src/OAuth2/OpenID/ResponseType/IdToken.php | 124 + .../OpenID/ResponseType/IdTokenInterface.php | 29 + .../OAuth2/OpenID/ResponseType/IdTokenToken.php | 27 + .../OpenID/ResponseType/IdTokenTokenInterface.php | 9 + .../OpenID/Storage/AuthorizationCodeInterface.php | 37 + .../OAuth2/OpenID/Storage/UserClaimsInterface.php | 38 + .../oauth2-server-php/src/OAuth2/Request.php | 213 ++ .../src/OAuth2/RequestInterface.php | 16 + .../oauth2-server-php/src/OAuth2/Response.php | 369 +++ .../src/OAuth2/ResponseInterface.php | 24 + .../src/OAuth2/ResponseType/AccessToken.php | 194 ++ .../OAuth2/ResponseType/AccessTokenInterface.php | 34 + .../src/OAuth2/ResponseType/AuthorizationCode.php | 100 + .../ResponseType/AuthorizationCodeInterface.php | 30 + .../src/OAuth2/ResponseType/JwtAccessToken.php | 124 + .../OAuth2/ResponseType/ResponseTypeInterface.php | 8 + .../oauth2-server-php/src/OAuth2/Scope.php | 103 + .../src/OAuth2/ScopeInterface.php | 40 + .../oauth2-server-php/src/OAuth2/Server.php | 879 ++++++ .../src/OAuth2/Storage/AccessTokenInterface.php | 64 + .../OAuth2/Storage/AuthorizationCodeInterface.php | 86 + .../src/OAuth2/Storage/Cassandra.php | 480 ++++ .../OAuth2/Storage/ClientCredentialsInterface.php | 49 + .../src/OAuth2/Storage/ClientInterface.php | 66 + .../src/OAuth2/Storage/CouchbaseDB.php | 331 +++ .../src/OAuth2/Storage/DynamoDB.php | 540 ++++ .../src/OAuth2/Storage/JwtAccessToken.php | 88 + .../src/OAuth2/Storage/JwtAccessTokenInterface.php | 14 + .../src/OAuth2/Storage/JwtBearerInterface.php | 74 + .../src/OAuth2/Storage/Memory.php | 381 +++ .../oauth2-server-php/src/OAuth2/Storage/Mongo.php | 392 +++ .../src/OAuth2/Storage/MongoDB.php | 380 +++ .../oauth2-server-php/src/OAuth2/Storage/Pdo.php | 553 ++++ .../src/OAuth2/Storage/PublicKeyInterface.php | 16 + .../oauth2-server-php/src/OAuth2/Storage/Redis.php | 321 +++ .../src/OAuth2/Storage/RefreshTokenInterface.php | 82 + .../src/OAuth2/Storage/ScopeInterface.php | 46 + .../OAuth2/Storage/UserCredentialsInterface.php | 52 + .../src/OAuth2/TokenType/Bearer.php | 130 + .../oauth2-server-php/src/OAuth2/TokenType/Mac.php | 22 + .../src/OAuth2/TokenType/TokenTypeInterface.php | 21 + .../oauth2-server-php/test/OAuth2/AutoloadTest.php | 16 + .../OAuth2/Controller/AuthorizeControllerTest.php | 492 ++++ .../OAuth2/Controller/ResourceControllerTest.php | 176 ++ .../test/OAuth2/Controller/TokenControllerTest.php | 289 ++ .../test/OAuth2/Encryption/FirebaseJwtTest.php | 102 + .../test/OAuth2/Encryption/JwtTest.php | 102 + .../OAuth2/GrantType/AuthorizationCodeTest.php | 223 ++ .../OAuth2/GrantType/ClientCredentialsTest.php | 159 ++ .../test/OAuth2/GrantType/ImplicitTest.php | 143 + .../test/OAuth2/GrantType/JwtBearerTest.php | 360 +++ .../test/OAuth2/GrantType/RefreshTokenTest.php | 204 ++ .../test/OAuth2/GrantType/UserCredentialsTest.php | 172 ++ .../OpenID/Controller/AuthorizeControllerTest.php | 182 ++ .../OpenID/Controller/UserInfoControllerTest.php | 44 + .../OpenID/GrantType/AuthorizationCodeTest.php | 57 + .../OAuth2/OpenID/ResponseType/CodeIdTokenTest.php | 182 ++ .../OAuth2/OpenID/ResponseType/IdTokenTest.php | 184 ++ .../OpenID/ResponseType/IdTokenTokenTest.php | 91 + .../OpenID/Storage/AuthorizationCodeTest.php | 95 + .../test/OAuth2/OpenID/Storage/UserClaimsTest.php | 41 + .../oauth2-server-php/test/OAuth2/RequestTest.php | 98 + .../oauth2-server-php/test/OAuth2/ResponseTest.php | 17 + .../test/OAuth2/ResponseType/AccessTokenTest.php | 107 + .../OAuth2/ResponseType/JwtAccessTokenTest.php | 160 ++ .../oauth2-server-php/test/OAuth2/ScopeTest.php | 42 + .../oauth2-server-php/test/OAuth2/ServerTest.php | 684 +++++ .../test/OAuth2/Storage/AccessTokenTest.php | 102 + .../test/OAuth2/Storage/AuthorizationCodeTest.php | 106 + .../test/OAuth2/Storage/ClientCredentialsTest.php | 28 + .../test/OAuth2/Storage/ClientTest.php | 110 + .../test/OAuth2/Storage/DynamoDBTest.php | 40 + .../test/OAuth2/Storage/JwtAccessTokenTest.php | 41 + .../test/OAuth2/Storage/JwtBearerTest.php | 25 + .../test/OAuth2/Storage/PdoTest.php | 39 + .../test/OAuth2/Storage/PublicKeyTest.php | 29 + .../test/OAuth2/Storage/RefreshTokenTest.php | 41 + .../test/OAuth2/Storage/ScopeTest.php | 53 + .../test/OAuth2/Storage/UserCredentialsTest.php | 40 + .../test/OAuth2/TokenType/BearerTest.php | 58 + .../bshaffer/oauth2-server-php/test/bootstrap.php | 12 + vendor/bshaffer/oauth2-server-php/test/cleanup.php | 15 + .../oauth2-server-php/test/config/keys/id_rsa | 15 + .../oauth2-server-php/test/config/keys/id_rsa.pub | 16 + .../oauth2-server-php/test/config/storage.json | 188 ++ .../test/lib/OAuth2/Request/TestRequest.php | 61 + .../test/lib/OAuth2/Storage/BaseTest.php | 36 + .../test/lib/OAuth2/Storage/Bootstrap.php | 967 +++++++ .../test/lib/OAuth2/Storage/NullStorage.php | 32 + vendor/composer/ClassLoader.php | 48 +- vendor/composer/LICENSE | 444 ++- vendor/composer/autoload_classmap.php | 619 ----- vendor/composer/autoload_namespaces.php | 1 + vendor/composer/autoload_real.php | 35 +- vendor/composer/installed.json | 76 +- 250 files changed, 16171 insertions(+), 18459 deletions(-) delete mode 100644 library/oauth2/.gitignore delete mode 100644 library/oauth2/.travis.yml delete mode 100644 library/oauth2/CHANGELOG.md delete mode 100644 library/oauth2/LICENSE delete mode 100644 library/oauth2/README.md delete mode 100644 library/oauth2/phpunit.xml delete mode 100644 library/oauth2/src/OAuth2/Autoloader.php delete mode 100644 library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php delete mode 100644 library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php delete mode 100644 library/oauth2/src/OAuth2/Controller/AuthorizeController.php delete mode 100644 library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php delete mode 100644 library/oauth2/src/OAuth2/Controller/ResourceController.php delete mode 100644 library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php delete mode 100644 library/oauth2/src/OAuth2/Controller/TokenController.php delete mode 100644 library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php delete mode 100644 library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php delete mode 100644 library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php delete mode 100644 library/oauth2/src/OAuth2/Encryption/Jwt.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/ClientCredentials.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/JwtBearer.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/RefreshToken.php delete mode 100644 library/oauth2/src/OAuth2/GrantType/UserCredentials.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php delete mode 100644 library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php delete mode 100644 library/oauth2/src/OAuth2/Request.php delete mode 100644 library/oauth2/src/OAuth2/RequestInterface.php delete mode 100644 library/oauth2/src/OAuth2/Response.php delete mode 100644 library/oauth2/src/OAuth2/ResponseInterface.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/AccessToken.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php delete mode 100644 library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php delete mode 100644 library/oauth2/src/OAuth2/Scope.php delete mode 100644 library/oauth2/src/OAuth2/ScopeInterface.php delete mode 100644 library/oauth2/src/OAuth2/Server.php delete mode 100644 library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/Cassandra.php delete mode 100644 library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/ClientInterface.php delete mode 100755 library/oauth2/src/OAuth2/Storage/CouchbaseDB.php delete mode 100644 library/oauth2/src/OAuth2/Storage/DynamoDB.php delete mode 100644 library/oauth2/src/OAuth2/Storage/JwtAccessToken.php delete mode 100644 library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/Memory.php delete mode 100644 library/oauth2/src/OAuth2/Storage/Mongo.php delete mode 100644 library/oauth2/src/OAuth2/Storage/Pdo.php delete mode 100644 library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/Redis.php delete mode 100644 library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/ScopeInterface.php delete mode 100644 library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php delete mode 100644 library/oauth2/src/OAuth2/TokenType/Bearer.php delete mode 100644 library/oauth2/src/OAuth2/TokenType/Mac.php delete mode 100644 library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php delete mode 100644 library/oauth2/test/OAuth2/AutoloadTest.php delete mode 100644 library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php delete mode 100644 library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php delete mode 100644 library/oauth2/test/OAuth2/Controller/TokenControllerTest.php delete mode 100644 library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php delete mode 100644 library/oauth2/test/OAuth2/Encryption/JwtTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/ImplicitTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php delete mode 100644 library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php delete mode 100644 library/oauth2/test/OAuth2/RequestTest.php delete mode 100644 library/oauth2/test/OAuth2/ResponseTest.php delete mode 100644 library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/ScopeTest.php delete mode 100644 library/oauth2/test/OAuth2/ServerTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/AccessTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/ClientTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/DynamoDBTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/JwtBearerTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/PdoTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/PublicKeyTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/ScopeTest.php delete mode 100644 library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php delete mode 100644 library/oauth2/test/OAuth2/TokenType/BearerTest.php delete mode 100644 library/oauth2/test/bootstrap.php delete mode 100644 library/oauth2/test/cleanup.php delete mode 100644 library/oauth2/test/config/keys/id_rsa delete mode 100644 library/oauth2/test/config/keys/id_rsa.pub delete mode 100644 library/oauth2/test/config/storage.json delete mode 100644 library/oauth2/test/lib/OAuth2/Request/TestRequest.php delete mode 100755 library/oauth2/test/lib/OAuth2/Storage/BaseTest.php delete mode 100755 library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php delete mode 100644 library/oauth2/test/lib/OAuth2/Storage/NullStorage.php create mode 100644 vendor/bshaffer/oauth2-server-php/CHANGELOG.md create mode 100644 vendor/bshaffer/oauth2-server-php/LICENSE create mode 100644 vendor/bshaffer/oauth2-server-php/README.md create mode 100644 vendor/bshaffer/oauth2-server-php/composer.json create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php create mode 100755 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/MongoDB.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php create mode 100644 vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/AutoloadTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/AuthorizeControllerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/ResourceControllerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Controller/TokenControllerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/FirebaseJwtTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Encryption/JwtTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/AuthorizationCodeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ClientCredentialsTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/ImplicitTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/JwtBearerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/RefreshTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/GrantType/UserCredentialsTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/OpenID/Storage/UserClaimsTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/RequestTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/AccessTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/ResponseType/JwtAccessTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/ScopeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/ServerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AccessTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/AuthorizationCodeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientCredentialsTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ClientTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/DynamoDBTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtAccessTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/JwtBearerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PdoTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/PublicKeyTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/RefreshTokenTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/ScopeTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/Storage/UserCredentialsTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/OAuth2/TokenType/BearerTest.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/bootstrap.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/cleanup.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa create mode 100644 vendor/bshaffer/oauth2-server-php/test/config/keys/id_rsa.pub create mode 100644 vendor/bshaffer/oauth2-server-php/test/config/storage.json create mode 100644 vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Request/TestRequest.php create mode 100755 vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/BaseTest.php create mode 100755 vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/Bootstrap.php create mode 100644 vendor/bshaffer/oauth2-server-php/test/lib/OAuth2/Storage/NullStorage.php diff --git a/composer.json b/composer.json index b59c81bba..e7577c41c 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "ext-openssl" : "*", "sabre/dav" : "~3.2", "michelf/php-markdown" : "^1.7", - "pixel418/markdownify": "^2.2" + "pixel418/markdownify": "^2.2", + "bshaffer/oauth2-server-php": "~1.8" }, "require-dev" : { "php" : ">=5.6", diff --git a/composer.lock b/composer.lock index 06fb17410..9f19b6f15 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,65 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "c0cafbf9fd702be588f6b392b9742cb6", + "hash": "85f6331e3e91b178ea0072065780747b", + "content-hash": "5aca7c342f023e1c3377a67c1812f5ff", "packages": [ + { + "name": "bshaffer/oauth2-server-php", + "version": "v1.9.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" + }, + "type": "library", + "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" + ], + "time": "2017-01-06 23:20:00" + }, { "name": "michelf/php-markdown", "version": "1.7.0", @@ -55,7 +112,7 @@ "keywords": [ "markdown" ], - "time": "2016-10-29T18:58:20+00:00" + "time": "2016-10-29 18:58:20" }, { "name": "pixel418/markdownify", @@ -111,7 +168,7 @@ "markdown", "markdownify" ], - "time": "2016-09-21T13:01:43+00:00" + "time": "2016-09-21 13:01:43" }, { "name": "psr/log", @@ -158,7 +215,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "sabre/dav", @@ -241,7 +298,7 @@ "framework", "iCalendar" ], - "time": "2016-06-28T02:44:05+00:00" + "time": "2016-06-28 02:44:05" }, { "name": "sabre/event", @@ -298,7 +355,7 @@ "promise", "signal" ], - "time": "2015-11-05T20:14:39+00:00" + "time": "2015-11-05 20:14:39" }, { "name": "sabre/http", @@ -353,7 +410,7 @@ "keywords": [ "http" ], - "time": "2016-01-06T23:00:08+00:00" + "time": "2016-01-06 23:00:08" }, { "name": "sabre/uri", @@ -404,7 +461,7 @@ "uri", "url" ], - "time": "2016-03-08T02:29:27+00:00" + "time": "2016-03-08 02:29:27" }, { "name": "sabre/vobject", @@ -501,7 +558,7 @@ "xCal", "xCard" ], - "time": "2016-07-15T19:52:17+00:00" + "time": "2016-07-15 19:52:17" }, { "name": "sabre/xml", @@ -564,2778 +621,10 @@ "dom", "xml" ], - "time": "2016-10-09T22:57:52+00:00" - } - ], - "packages-dev": [ - { - "name": "behat/behat", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/Behat/Behat.git", - "reference": "15a3a1857457eaa29cdf41564a5e421effb09526" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/15a3a1857457eaa29cdf41564a5e421effb09526", - "reference": "15a3a1857457eaa29cdf41564a5e421effb09526", - "shasum": "" - }, - "require": { - "behat/gherkin": "^4.4.4", - "behat/transliterator": "~1.0", - "container-interop/container-interop": "^1.1", - "ext-mbstring": "*", - "php": ">=5.3.3", - "symfony/class-loader": "~2.1||~3.0", - "symfony/config": "~2.3||~3.0", - "symfony/console": "~2.5||~3.0", - "symfony/dependency-injection": "~2.1||~3.0", - "symfony/event-dispatcher": "~2.1||~3.0", - "symfony/translation": "~2.3||~3.0", - "symfony/yaml": "~2.1||~3.0" - }, - "require-dev": { - "herrera-io/box": "~1.6.1", - "phpunit/phpunit": "~4.5", - "symfony/process": "~2.5|~3.0" - }, - "suggest": { - "behat/mink-extension": "for integration with Mink testing framework", - "behat/symfony2-extension": "for integration with Symfony2 web framework", - "behat/yii-extension": "for integration with Yii web framework" - }, - "bin": [ - "bin/behat" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Behat": "src/", - "Behat\\Testwork": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Scenario-oriented BDD framework for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "Agile", - "BDD", - "ScenarioBDD", - "Scrum", - "StoryBDD", - "User story", - "business", - "development", - "documentation", - "examples", - "symfony", - "testing" - ], - "time": "2016-12-25T13:43:52+00:00" - }, - { - "name": "behat/gherkin", - "version": "v4.4.5", - "source": { - "type": "git", - "url": "https://github.com/Behat/Gherkin.git", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", - "shasum": "" - }, - "require": { - "php": ">=5.3.1" - }, - "require-dev": { - "phpunit/phpunit": "~4.5|~5", - "symfony/phpunit-bridge": "~2.7|~3", - "symfony/yaml": "~2.3|~3" - }, - "suggest": { - "symfony/yaml": "If you want to parse features, represented in YAML files" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Gherkin": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Gherkin DSL parser for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "Cucumber", - "DSL", - "gherkin", - "parser" - ], - "time": "2016-10-30T11:50:56+00:00" - }, - { - "name": "behat/mink", - "version": "v1.7.1", - "source": { - "type": "git", - "url": "https://github.com/minkphp/Mink.git", - "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/Mink/zipball/e6930b9c74693dff7f4e58577e1b1743399f3ff9", - "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/css-selector": "~2.1|~3.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "suggest": { - "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", - "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", - "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", - "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Browser controller/emulator abstraction for PHP", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "testing", - "web" - ], - "time": "2016-03-05T08:26:18+00:00" - }, - { - "name": "behat/mink-browserkit-driver", - "version": "v1.3.2", - "source": { - "type": "git", - "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", - "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/10e67fb4a295efcd62ea0bf16025a85ea19534fb", - "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb", - "shasum": "" - }, - "require": { - "behat/mink": "^1.7.1@dev", - "php": ">=5.3.6", - "symfony/browser-kit": "~2.3|~3.0", - "symfony/dom-crawler": "~2.3|~3.0" - }, - "require-dev": { - "silex/silex": "~1.2", - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\Driver\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Symfony2 BrowserKit driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "Mink", - "Symfony2", - "browser", - "testing" - ], - "time": "2016-03-05T08:59:47+00:00" - }, - { - "name": "behat/mink-extension", - "version": "v2.2", - "source": { - "type": "git", - "url": "https://github.com/Behat/MinkExtension.git", - "reference": "5b4bda64ff456104564317e212c823e45cad9d59" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/MinkExtension/zipball/5b4bda64ff456104564317e212c823e45cad9d59", - "reference": "5b4bda64ff456104564317e212c823e45cad9d59", - "shasum": "" - }, - "require": { - "behat/behat": "~3.0,>=3.0.5", - "behat/mink": "~1.5", - "php": ">=5.3.2", - "symfony/config": "~2.2|~3.0" - }, - "require-dev": { - "behat/mink-goutte-driver": "~1.1", - "phpspec/phpspec": "~2.0" - }, - "type": "behat-extension", - "extra": { - "branch-alias": { - "dev-master": "2.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\MinkExtension": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - }, - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com" - } - ], - "description": "Mink extension for Behat", - "homepage": "http://extensions.behat.org/mink", - "keywords": [ - "browser", - "gui", - "test", - "web" - ], - "time": "2016-02-15T07:55:18+00:00" - }, - { - "name": "behat/mink-goutte-driver", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/minkphp/MinkGoutteDriver.git", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", - "shasum": "" - }, - "require": { - "behat/mink": "~1.6@dev", - "behat/mink-browserkit-driver": "~1.2@dev", - "fabpot/goutte": "~1.0.4|~2.0|~3.1", - "php": ">=5.3.1" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\Driver\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Goutte driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "goutte", - "headless", - "testing" - ], - "time": "2016-03-05T09:04:22+00:00" - }, - { - "name": "behat/transliterator", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/Behat/Transliterator.git", - "reference": "868e05be3a9f25ba6424c2dd4849567f50715003" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Transliterator/zipball/868e05be3a9f25ba6424c2dd4849567f50715003", - "reference": "868e05be3a9f25ba6424c2dd4849567f50715003", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Transliterator": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Artistic-1.0" - ], - "description": "String transliterator", - "keywords": [ - "i18n", - "slug", - "transliterator" - ], - "time": "2015-09-28T16:26:35+00:00" - }, - { - "name": "container-interop/container-interop", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/container-interop/container-interop.git", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "shasum": "" - }, - "require": { - "psr/container": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Interop\\Container\\": "src/Interop/Container/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14T19:40:03+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14T21:17:01+00:00" - }, - { - "name": "fabpot/goutte", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Goutte.git", - "reference": "db5c28f4a010b4161d507d5304e28a7ebf211638" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/db5c28f4a010b4161d507d5304e28a7ebf211638", - "reference": "db5c28f4a010b4161d507d5304e28a7ebf211638", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^6.0", - "php": ">=5.5.0", - "symfony/browser-kit": "~2.1|~3.0", - "symfony/css-selector": "~2.1|~3.0", - "symfony/dom-crawler": "~2.1|~3.0" - }, - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Goutte\\": "Goutte" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "A simple PHP Web Scraper", - "homepage": "https://github.com/FriendsOfPHP/Goutte", - "keywords": [ - "scraper" - ], - "time": "2017-01-03T13:21:43+00:00" - }, - { - "name": "guzzlehttp/guzzle", - "version": "6.2.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60", - "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60", - "shasum": "" - }, - "require": { - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.3.1", - "php": ">=5.5" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.0", - "psr/log": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.2-dev" - } - }, - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2016-10-08T15:01:37+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "v1.3.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "time": "2016-12-20T10:07:11+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "04a6d1a00ea5da0727ee94309a9f0d3dbaecb569" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/04a6d1a00ea5da0727ee94309a9f0d3dbaecb569", - "reference": "04a6d1a00ea5da0727ee94309a9f0d3dbaecb569", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "request", - "response", - "stream", - "uri", - "url" - ], - "time": "2017-02-21T01:20:32+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/5a5a9fc8025a08d8919be87d6884d5a92520cefe", - "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2017-01-26T22:05:40+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2015-12-27T11:43:31+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30T07:12:33+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "time": "2016-11-25T06:54:22+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.6.2", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0|^2.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.0", - "phpunit/phpunit": "^4.8 || ^5.6.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2016-11-21T14:58:47+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca060f645beeddebedb1885c97bf163e93264c35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca060f645beeddebedb1885c97bf163e93264c35", - "reference": "ca060f645beeddebedb1885c97bf163e93264c35", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "^1.4.2 || ^2.0", - "sebastian/code-unit-reverse-lookup": "~1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "~1.0|~2.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.4.0", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2017-02-23T07:38:02+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2016-10-03T07:40:28+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4|~5" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2016-05-12T18:03:57+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.10", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "284fb0679dd25fb5ffb56dad92c72860c0a22f1b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/284fb0679dd25fb5ffb56dad92c72860c0a22f1b", - "reference": "284fb0679dd25fb5ffb56dad92c72860c0a22f1b", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2017-02-23T06:14:45+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "5.7.14", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4906b8faf23e42612182fd212eb6f4c0f2954b57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4906b8faf23e42612182fd212eb6f4c0f2954b57", - "reference": "4906b8faf23e42612182fd212eb6f4c0f2954b57", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "^1.2.4", - "sebastian/diff": "~1.2", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0.3|~2.0", - "symfony/yaml": "~2.1|~3.0" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2017-02-19T07:22:16+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "3.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2016-12-08T20:27:08+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", - "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2016-02-13T06:45:14+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2015-12-08T07:14:41+00:00" - }, - { - "name": "sebastian/environment", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-11-26T07:53:53+00:00" - }, - { - "name": "sebastian/exporter", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2016-11-19T08:54:04+00:00" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12T03:26:01+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "symfony/browser-kit", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "394a2475a3a89089353fde5714a7f402fbb83880" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/394a2475a3a89089353fde5714a7f402fbb83880", - "reference": "394a2475a3a89089353fde5714a7f402fbb83880", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/dom-crawler": "~2.8|~3.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" - }, - "suggest": { - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony BrowserKit Component", - "homepage": "https://symfony.com", - "time": "2017-01-31T21:49:23+00:00" - }, - { - "name": "symfony/class-loader", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/class-loader.git", - "reference": "2847d56f518ad5721bf85aa9174b3aa3fd12aa03" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/class-loader/zipball/2847d56f518ad5721bf85aa9174b3aa3fd12aa03", - "reference": "2847d56f518ad5721bf85aa9174b3aa3fd12aa03", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "symfony/finder": "~2.8|~3.0", - "symfony/polyfill-apcu": "~1.1" - }, - "suggest": { - "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\ClassLoader\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony ClassLoader Component", - "homepage": "https://symfony.com", - "time": "2017-01-21T17:06:35+00:00" - }, - { - "name": "symfony/config", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "9f99453e77771e629af8a25eeb0a6c4ed1e19da2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9f99453e77771e629af8a25eeb0a6c4ed1e19da2", - "reference": "9f99453e77771e629af8a25eeb0a6c4ed1e19da2", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/filesystem": "~2.8|~3.0" - }, - "require-dev": { - "symfony/yaml": "~3.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Config Component", - "homepage": "https://symfony.com", - "time": "2017-02-14T16:27:43+00:00" - }, - { - "name": "symfony/console", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0e5e6899f82230fcb1153bcaf0e106ffaa44b870", - "reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/debug": "~2.8|~3.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/filesystem": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/filesystem": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T14:07:22+00:00" - }, - { - "name": "symfony/css-selector", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f0e628f04fc055c934b3211cfabdb1c59eefbfaa", - "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "https://symfony.com", - "time": "2017-01-02T20:32:22+00:00" - }, - { - "name": "symfony/debug", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/9b98854cb45bc59d100b7d4cc4cf9e05f21026b9", - "reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T16:34:18+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "130aa55b8ed7e6d0d75b0ed37256cec687a22f41" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/130aa55b8ed7e6d0d75b0ed37256cec687a22f41", - "reference": "130aa55b8ed7e6d0d75b0ed37256cec687a22f41", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "conflict": { - "symfony/yaml": "<3.2" - }, - "require-dev": { - "symfony/config": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/yaml": "~3.2" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DependencyInjection Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T22:46:52+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "b814b41373fc4e535aff8c765abe39545216f391" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b814b41373fc4e535aff8c765abe39545216f391", - "reference": "b814b41373fc4e535aff8c765abe39545216f391", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2017-01-21T17:14:11+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9137eb3a3328e413212826d63eeeb0217836e2b6", - "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2017-01-02T20:32:22+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "a0c6ef2dc78d33b58d91d3a49f49797a184d06f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/a0c6ef2dc78d33b58d91d3a49f49797a184d06f4", - "reference": "a0c6ef2dc78d33b58d91d3a49f49797a184d06f4", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "https://symfony.com", - "time": "2017-01-08T20:47:33+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2016-11-14T01:06:16+00:00" - }, - { - "name": "symfony/translation", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "d6825c6bb2f1da13f564678f9f236fe8242c0029" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/d6825c6bb2f1da13f564678f9f236fe8242c0029", - "reference": "d6825c6bb2f1da13f564678f9f236fe8242c0029", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/config": "<2.8" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/intl": "~2.8|~3.0", - "symfony/yaml": "~2.8|~3.0" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Translation Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T22:46:52+00:00" - }, - { - "name": "symfony/yaml", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "9724c684646fcb5387d579b4bfaa63ee0b0c64c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/9724c684646fcb5387d579b4bfaa63ee0b0c64c8", - "reference": "9724c684646fcb5387d579b4bfaa63ee0b0c64c8", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "symfony/console": "~2.8|~3.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T22:46:52+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2016-10-09 22:57:52" } ], + "packages-dev": null, "aliases": [], "minimum-stability": "stable", "stability-flags": { @@ -3353,7 +642,5 @@ "ext-xml": "*", "ext-openssl": "*" }, - "platform-dev": { - "php": ">=5.6" - } + "platform-dev": [] } diff --git a/library/oauth2/.gitignore b/library/oauth2/.gitignore deleted file mode 100644 index c43a667d4..000000000 --- a/library/oauth2/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Test Files # -test/config/test.sqlite -vendor -composer.lock -.idea diff --git a/library/oauth2/.travis.yml b/library/oauth2/.travis.yml deleted file mode 100644 index dd4aae4a6..000000000 --- a/library/oauth2/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: php -sudo: false -cache: - directories: - - $HOME/.composer/cache - - vendor -php: -- 5.3 -- 5.4 -- 5.5 -- 5.6 -- 7 -- hhvm -env: - global: - - SKIP_MONGO_TESTS=1 - - secure: Bc5ZqvZ1YYpoPZNNuU2eCB8DS6vBYrAdfBtTenBs5NSxzb+Vjven4kWakbzaMvZjb/Ib7Uph7DGuOtJXpmxnvBXPLd707LZ89oFWN/yqQlZKCcm8iErvJCB5XL+/ONHj2iPdR242HJweMcat6bMCwbVWoNDidjtWMH0U2mYFy3M= - - secure: R3bXlymyFiY2k2jf7+fv/J8i34wtXTkmD4mCr5Ps/U+vn9axm2VtvR2Nj+r7LbRjn61gzFE/xIVjYft/wOyBOYwysrfriydrnRVS0owh6y+7EyOyQWbRX11vVQMf8o31QCQE5BY58V5AJZW3MjoOL0FVlTgySJiJvdw6Pv18v+E= -services: -- mongodb -- redis-server -- cassandra -before_install: -- phpenv config-rm xdebug.ini || return 0 -install: -- composer install --no-interaction -before_script: -- psql -c 'create database oauth2_server_php;' -U postgres -after_script: -- php test/cleanup.php diff --git a/library/oauth2/CHANGELOG.md b/library/oauth2/CHANGELOG.md deleted file mode 100644 index 03d925e06..000000000 --- a/library/oauth2/CHANGELOG.md +++ /dev/null @@ -1,152 +0,0 @@ -CHANGELOG for 1.x -================= - -This changelog references the relevant changes (bug and security fixes) done -in 1.x minor versions. - -To see the files changed for a given bug, go to https://github.com/bshaffer/oauth2-server-php/issues/### where ### is the bug number -To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1 -To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash - -* 1.8.0 (2015-09-18) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/643 - - * bug #594 - adds jti - * bug #598 - fixes lifetime configurations for JWTs - * bug #634 - fixes travis builds, upgrade to containers - * bug #586 - support for revoking tokens - * bug #636 - Adds FirebaseJWT bridge - * bug #639 - Mongo HHVM compatibility - -* 1.7.0 (2015-04-23) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/572 - - * bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC - * bug #508 - Case insensitive for Bearer token header name ba716d4 - * bug #512 - validateRedirectUri is now public - * bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage - * bug #505 - DynamoDB storage fixes - * bug #556 - adds "code id_token" return type to openid connect - * bug #563 - Include "issuer" config key for JwtAccessToken - * bug #564 - Fixes JWT vulnerability - * bug #571 - Added unset_refresh_token_after_use option - -* 1.6 (2015-01-16) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/496 - - * bug 437 - renames CryptoToken to JwtAccessToken / use_crypto_tokens to use_jwt_access_tokens - * bug 447 - Adds a Couchbase storage implementation - * bug 460 - Rename JWT claims to match spec - * bug 470 - order does not matter for multi-valued response types - * bug 471 - Make validateAuthorizeRequest available for POST in addition to GET - * bug 475 - Adds JTI table definitiion - * bug 481 - better randomness for generating access tokens - * bug 480 - Use hash_equals() for signature verification (prevents remote timing attacks) - * bugs 489, 491, 498 - misc other fixes - -* 1.5 (2014-08-27) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/446 - - * bug #399 - Add DynamoDB Support - * bug #404 - renamed error name for malformed/expired tokens - * bug #412 - Openid connect: fixes for claims with more than one scope / Add support for the prompt parameter ('consent' and 'none') - * bug #411 - fixes xml output - * bug #413 - fixes invalid format error - * bug #401 - fixes code standards / whitespace - * bug #354 - bundles PDO SQL with the library - * [BC] bug #397 - refresh tokens should not be encrypted - * bug #423 - makes "scope" optional for refresh token storage - -* 1.4 (2014-06-12) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/392 - - * bug #189 Storage\PDO - allows DSN string in constructor - * bug #233 Bearer Tokens - allows token in request body for PUT requests - * bug #346 Fixes open_basedir warning - * bug #351 Adds OpenID Connect support - * bug #355 Adds php 5.6 and HHVM to travis.ci testing - * [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface - * bug #363 Encryption\JWT - Allows for subclassing JWT Headers - * bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional - * bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected - * bug #323 ResourceController - client_id is no longer required to be returned when calling getAccessToken - * bug #367 Storage\PDO - adds Postgres support - * bug #368 Access Tokens - use mcrypt_create_iv or openssl_random_pseudo_bytes to create token string - * bug #376 Request - allows case insensitive headers - * bug #384 Storage\PDO - can pass in PDO options in constructor of PDO storage - * misc fixes #361, #292, #373, #374, #379, #396 -* 1.3 (2014-02-27) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/325 - - * bug #311 adds cassandra storage - * bug #298 fixes response code for user credentials grant type - * bug #318 adds 'use_crypto_tokens' config to Server class for better DX - * [BC] bug #320 pass client_id to getDefaultScope - * bug #324 better feedback when running tests - * bug #335 adds support for non-expiring refresh tokens - * bug #333 fixes Pdo storage for getClientKey - * bug #336 fixes Redis storage for expireAuthorizationCode - -* 1.2 (2014-01-03) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/288 - - * bug #285 changed response header from 200 to 401 when empty token received - * bug #286 adds documentation and links to spec for not including error messages when no token is supplied - * bug #280 ensures PHP warnings do not get thrown as a result of an invalid argument to $jwt->decode() - * bug #279 predis wrong number of arguments - * bug #277 Securing JS WebApp client secret w/ password grant type - -* 1.1 (2013-12-17) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/276 - - * bug #278 adds refresh token configuration to Server class - * bug #274 Supplying a null client_id and client_secret grants API access - * bug #244 [MongoStorage] More detailed implementation info - * bug #268 Implement jti for JWT Bearer tokens to prevent replay attacks. - * bug #266 Removing unused argument to getAccessTokenData - * bug #247 Make Bearer token type consistent - * bug #253 Fixing CryptoToken refresh token lifetime - * bug #246 refactors public key logic to be more intuitive - * bug #245 adds support for JSON crypto tokens - * bug #230 Remove unused columns in oauth_clients - * bug #215 makes Redis Scope Storage obey the same paradigm as PDO - * bug #228 removes scope group - * bug #227 squelches open basedir restriction error - * bug #223 Updated docblocks for RefreshTokenInterface.php - * bug #224 Adds protected properties - * bug #217 Implement ScopeInterface for PDO, Redis - -* 1.0 (2013-08-12) - - * bug #203 Add redirect\_status_code config param for AuthorizeController - * bug #205 ensures unnecessary ? is not set when ** bug - * bug #204 Fixed call to LogicException - * bug #202 Add explode to checkRestrictedGrant in PDO Storage - * bug #197 adds support for 'false' default scope ** bug - * bug #192 reference errors and adds tests - * bug #194 makes some appropriate properties ** bug - * bug #191 passes config to HttpBasic - * bug #190 validates client credentials before ** bug - * bug #171 Fix wrong redirect following authorization step - * bug #187 client_id is now passed to getDefaultScope(). - * bug #176 Require refresh_token in getRefreshToken response - * bug #174 make user\_id not required for refresh_token grant - * bug #173 Duplication in JwtBearer Grant - * bug #168 user\_id not required for authorization_code grant - * bug #133 hardens default security for user object - * bug #163 allows redirect\_uri on authorization_code to be NULL in docs example - * bug #162 adds getToken on ResourceController for convenience - * bug #161 fixes fatal error - * bug #163 Invalid redirect_uri handling - * bug #156 user\_id in OAuth2\_Storage_AuthorizationCodeInterface::getAuthorizationCode() response - * bug #157 Fix for extending access and refresh tokens - * bug #154 ResponseInterface: getParameter method is used in the library but not defined in the interface - * bug #148 Add more detail to examples in Readme.md diff --git a/library/oauth2/LICENSE b/library/oauth2/LICENSE deleted file mode 100644 index d7ece8467..000000000 --- a/library/oauth2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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/library/oauth2/README.md b/library/oauth2/README.md deleted file mode 100644 index 4ceda6cf9..000000000 --- a/library/oauth2/README.md +++ /dev/null @@ -1,8 +0,0 @@ -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/library/oauth2/phpunit.xml b/library/oauth2/phpunit.xml deleted file mode 100644 index e36403f0a..000000000 --- a/library/oauth2/phpunit.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - ./test/OAuth2/ - - - - - - ./src/OAuth2/ - - - diff --git a/library/oauth2/src/OAuth2/Autoloader.php b/library/oauth2/src/OAuth2/Autoloader.php deleted file mode 100644 index ecfb6ba75..000000000 --- a/library/oauth2/src/OAuth2/Autoloader.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @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/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php b/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php deleted file mode 100644 index 29c7171b5..000000000 --- a/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php +++ /dev/null @@ -1,15 +0,0 @@ - - */ -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 - * - * $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 - * ); - * - */ - 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/library/oauth2/src/OAuth2/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/Controller/AuthorizeController.php deleted file mode 100644 index a9a722587..000000000 --- a/library/oauth2/src/OAuth2/Controller/AuthorizeController.php +++ /dev/null @@ -1,388 +0,0 @@ - - * $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 - * ); - * - * @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope - */ - public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null) - { - $this->clientStorage = $clientStorage; - $this->responseTypes = $responseTypes; - $this->config = array_merge(array( - 'allow_implicit' => false, - 'enforce_state' => true, - 'require_exact_redirect_uri' => true, - 'redirect_status_code' => 302, - ), $config); - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) - { - if (!is_bool($is_authorized)) { - throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.'); - } - - // We repeat this, because we need to re-validate. The request could be POSTed - // by a 3rd-party (because we are not internally enforcing NONCEs, etc) - if (!$this->validateAuthorizeRequest($request, $response)) { - return; - } - - // If no redirect_uri is passed in the request, use client's registered one - if (empty($this->redirect_uri)) { - $clientData = $this->clientStorage->getClientDetails($this->client_id); - $registered_redirect_uri = $clientData['redirect_uri']; - } - - // the user declined access to the client's application - if ($is_authorized === false) { - $redirect_uri = $this->redirect_uri ?: $registered_redirect_uri; - $this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id); - - return; - } - - // build the parameters to set in the redirect URI - if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) { - return; - } - - $authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id); - - list($redirect_uri, $uri_params) = $authResult; - - if (empty($redirect_uri) && !empty($registered_redirect_uri)) { - $redirect_uri = $registered_redirect_uri; - } - - $uri = $this->buildUri($redirect_uri, $uri_params); - - // return redirect response - $response->setRedirect($this->config['redirect_status_code'], $uri); - } - - protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) - { - $error = 'access_denied'; - $error_message = 'The user denied access to your application'; - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message); - } - - /* - * We have made this protected so this class can be extended to add/modify - * these parameters - */ - protected function buildAuthorizeParameters($request, $response, $user_id) - { - // @TODO: we should be explicit with this in the future - $params = array( - 'scope' => $this->scope, - 'state' => $this->state, - 'client_id' => $this->client_id, - 'redirect_uri' => $this->redirect_uri, - 'response_type' => $this->response_type, - ); - - return $params; - } - - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) - { - // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI) - if (!$client_id = $request->query('client_id', $request->request('client_id'))) { - // We don't have a good URI to use - $response->setError(400, 'invalid_client', "No client id supplied"); - - return false; - } - - // Get client details - if (!$clientData = $this->clientStorage->getClientDetails($client_id)) { - $response->setError(400, 'invalid_client', 'The client id supplied is invalid'); - - return false; - } - - $registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : ''; - - // Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI. - // @see http://tools.ietf.org/html/rfc6749#section-3.1.2 - // @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1 - // @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1 - if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) { - // validate there is no fragment supplied - $parts = parse_url($supplied_redirect_uri); - if (isset($parts['fragment']) && $parts['fragment']) { - $response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment'); - - return false; - } - - // validate against the registered redirect uri(s) if available - if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) { - $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2'); - - return false; - } - $redirect_uri = $supplied_redirect_uri; - } else { - // use the registered redirect_uri if none has been supplied, if possible - if (!$registered_redirect_uri) { - $response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored'); - - return false; - } - - if (count(explode(' ', $registered_redirect_uri)) > 1) { - $response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3'); - - return false; - } - $redirect_uri = $registered_redirect_uri; - } - - // Select the redirect URI - $response_type = $request->query('response_type', $request->request('response_type')); - - // for multiple-valued response types - make them alphabetical - if (false !== strpos($response_type, ' ')) { - $types = explode(' ', $response_type); - sort($types); - $response_type = ltrim(implode(' ', $types)); - } - - $state = $request->query('state', $request->request('state')); - - // type and client_id are required - if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null); - - return false; - } - - if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { - if (!isset($this->responseTypes['code'])) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null); - - return false; - } - if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); - - return false; - } - if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) { - $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied'); - - return false; - } - } else { - if (!$this->config['allow_implicit']) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null); - - return false; - } - if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); - - return false; - } - } - - // validate requested scope if it exists - $requestedScope = $this->scopeUtil->getScopeFromRequest($request); - - if ($requestedScope) { - // restrict scope by client specific scope if applicable, - // otherwise verify the scope exists - $clientScope = $this->clientStorage->getClientScope($client_id); - if ((empty($clientScope) && !$this->scopeUtil->scopeExists($requestedScope)) - || (!empty($clientScope) && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null); - - return false; - } - } else { - // use a globally-defined default scope - $defaultScope = $this->scopeUtil->getDefaultScope($client_id); - - if (false === $defaultScope) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null); - - return false; - } - - $requestedScope = $defaultScope; - } - - // Validate state parameter exists (if configured to enforce this) - if ($this->config['enforce_state'] && !$state) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required'); - - return false; - } - - // save the input data and return true - $this->scope = $requestedScope; - $this->state = $state; - $this->client_id = $client_id; - // Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3) - $this->redirect_uri = $supplied_redirect_uri; - $this->response_type = $response_type; - - return true; - } - - /** - * Build the absolute URI based on supplied URI and parameters. - * - * @param $uri An absolute URI. - * @param $params Parameters to be append as GET. - * - * @return - * An absolute URI with supplied parameters. - * - * @ingroup oauth2_section_4 - */ - private function buildUri($uri, $params) - { - $parse_url = parse_url($uri); - - // Add our params to the parsed uri - foreach ($params as $k => $v) { - if (isset($parse_url[$k])) { - $parse_url[$k] .= "&" . http_build_query($v, '', '&'); - } else { - $parse_url[$k] = http_build_query($v, '', '&'); - } - } - - // Put humpty dumpty back together - return - ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "") - . ((isset($parse_url["user"])) ? $parse_url["user"] - . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "") - . ((isset($parse_url["host"])) ? $parse_url["host"] : "") - . ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "") - . ((isset($parse_url["path"])) ? $parse_url["path"] : "") - . ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "") - . ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "") - ; - } - - protected function getValidResponseTypes() - { - return array( - self::RESPONSE_TYPE_ACCESS_TOKEN, - self::RESPONSE_TYPE_AUTHORIZATION_CODE, - ); - } - - /** - * Internal method for validating redirect URI supplied - * - * @param string $inputUri The submitted URI to be validated - * @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to - * allow for multiple URIs - * - * @see http://tools.ietf.org/html/rfc6749#section-3.1.2 - */ - protected function validateRedirectUri($inputUri, $registeredUriString) - { - if (!$inputUri || !$registeredUriString) { - return false; // if either one is missing, assume INVALID - } - - $registered_uris = explode(' ', $registeredUriString); - foreach ($registered_uris as $registered_uri) { - if ($this->config['require_exact_redirect_uri']) { - // the input uri is validated against the registered uri using exact match - if (strcmp($inputUri, $registered_uri) === 0) { - return true; - } - } else { - $registered_uri_length = strlen($registered_uri); - if ($registered_uri_length === 0) { - return false; - } - - // the input uri is validated against the registered uri using case-insensitive match of the initial string - // i.e. additional query parameters may be applied - if (strcasecmp(substr($inputUri, 0, $registered_uri_length), $registered_uri) === 0) { - return true; - } - } - } - - return false; - } - - /** - * Convenience methods to access the parameters derived from the validated request - */ - - public function getScope() - { - return $this->scope; - } - - public function getState() - { - return $this->state; - } - - public function getClientId() - { - return $this->client_id; - } - - public function getRedirectUri() - { - return $this->redirect_uri; - } - - public function getResponseType() - { - return $this->response_type; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php deleted file mode 100644 index fa07ae8d2..000000000 --- a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php +++ /dev/null @@ -1,43 +0,0 @@ - $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/library/oauth2/src/OAuth2/Controller/ResourceController.php b/library/oauth2/src/OAuth2/Controller/ResourceController.php deleted file mode 100644 index e8588188f..000000000 --- a/library/oauth2/src/OAuth2/Controller/ResourceController.php +++ /dev/null @@ -1,111 +0,0 @@ -tokenType = $tokenType; - $this->tokenStorage = $tokenStorage; - - $this->config = array_merge(array( - 'www_realm' => 'Service', - ), $config); - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null) - { - $token = $this->getAccessTokenData($request, $response); - - // Check if we have token data - if (is_null($token)) { - return false; - } - - /** - * Check scope, if provided - * If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403 - * @see http://tools.ietf.org/html/rfc6750#section-3.1 - */ - if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) { - $response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token'); - $response->addHttpHeaders(array( - 'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"', - $this->tokenType->getTokenType(), - $this->config['www_realm'], - $scope, - $response->getParameter('error'), - $response->getParameter('error_description') - ) - )); - - return false; - } - - // allow retrieval of the token - $this->token = $token; - - return (bool) $token; - } - - public function getAccessTokenData(RequestInterface $request, ResponseInterface $response) - { - // Get the token parameter - if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) { - // Get the stored token data (from the implementing subclass) - // Check we have a well formed token - // Check token expiration (expires is a mandatory paramter) - if (!$token = $this->tokenStorage->getAccessToken($token_param)) { - $response->setError(401, 'invalid_token', 'The access token provided is invalid'); - } elseif (!isset($token["expires"]) || !isset($token["client_id"])) { - $response->setError(401, 'malformed_token', 'Malformed token (missing "expires")'); - } elseif (time() > $token["expires"]) { - $response->setError(401, 'expired_token', 'The access token provided has expired'); - } else { - return $token; - } - } - - $authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']); - - if ($error = $response->getParameter('error')) { - $authHeader = sprintf('%s, error="%s"', $authHeader, $error); - if ($error_description = $response->getParameter('error_description')) { - $authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description); - } - } - - $response->addHttpHeaders(array('WWW-Authenticate' => $authHeader)); - - return null; - } - - // convenience method to allow retrieval of the token - public function getToken() - { - return $this->token; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php b/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php deleted file mode 100644 index 611421935..000000000 --- a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php +++ /dev/null @@ -1,26 +0,0 @@ - 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/library/oauth2/src/OAuth2/Controller/TokenController.php b/library/oauth2/src/OAuth2/Controller/TokenController.php deleted file mode 100644 index 42dab892f..000000000 --- a/library/oauth2/src/OAuth2/Controller/TokenController.php +++ /dev/null @@ -1,278 +0,0 @@ -clientAssertionType = $clientAssertionType; - $this->accessToken = $accessToken; - $this->clientStorage = $clientStorage; - foreach ($grantTypes as $grantType) { - $this->addGrantType($grantType); - } - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response) - { - if ($token = $this->grantAccessToken($request, $response)) { - // @see http://tools.ietf.org/html/rfc6749#section-5.1 - // server MUST disable caching in headers when tokens are involved - $response->setStatusCode(200); - $response->addParameters($token); - $response->addHttpHeaders(array( - 'Cache-Control' => 'no-store', - 'Pragma' => 'no-cache', - 'Content-Type' => 'application/json' - )); - } - } - - /** - * Grant or deny a requested access token. - * This would be called from the "/token" endpoint as defined in the spec. - * You can call your endpoint whatever you want. - * - * @param $request - RequestInterface - * Request object to grant access token - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @see http://tools.ietf.org/html/rfc6749#section-10.6 - * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 - * - * @ingroup oauth2_section_4 - */ - public function grantAccessToken(RequestInterface $request, ResponseInterface $response) - { - if (strtolower($request->server('REQUEST_METHOD')) != 'post') { - $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); - $response->addHttpHeaders(array('Allow' => 'POST')); - - return null; - } - - /** - * Determine grant type from request - * and validate the request for that grant type - */ - if (!$grantTypeIdentifier = $request->request('grant_type')) { - $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); - - return null; - } - - if (!isset($this->grantTypes[$grantTypeIdentifier])) { - /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ - $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); - - return null; - } - - $grantType = $this->grantTypes[$grantTypeIdentifier]; - - /** - * Retrieve the client information from the request - * ClientAssertionTypes allow for grant types which also assert the client data - * in which case ClientAssertion is handled in the validateRequest method - * - * @see OAuth2\GrantType\JWTBearer - * @see OAuth2\GrantType\ClientCredentials - */ - if (!$grantType instanceof ClientAssertionTypeInterface) { - if (!$this->clientAssertionType->validateRequest($request, $response)) { - return null; - } - $clientId = $this->clientAssertionType->getClientId(); - } - - /** - * Retrieve the grant type information from the request - * The GrantTypeInterface object handles all validation - * If the object is an instance of ClientAssertionTypeInterface, - * That logic is handled here as well - */ - if (!$grantType->validateRequest($request, $response)) { - return null; - } - - if ($grantType instanceof ClientAssertionTypeInterface) { - $clientId = $grantType->getClientId(); - } else { - // validate the Client ID (if applicable) - if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { - $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); - - return null; - } - } - - /** - * Validate the client can use the requested grant type - */ - if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) { - $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); - - return false; - } - - /** - * Validate the scope of the token - * - * requestedScope - the scope specified in the token request - * availableScope - the scope associated with the grant type - * ex: in the case of the "Authorization Code" grant type, - * the scope is specified in the authorize request - * - * @see http://tools.ietf.org/html/rfc6749#section-3.3 - */ - - $requestedScope = $this->scopeUtil->getScopeFromRequest($request); - $availableScope = $grantType->getScope(); - - if ($requestedScope) { - // validate the requested scope - if ($availableScope) { - if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) { - $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request'); - - return null; - } - } else { - // validate the client has access to this scope - if ($clientScope = $this->clientStorage->getClientScope($clientId)) { - if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) { - $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client'); - - return false; - } - } elseif (!$this->scopeUtil->scopeExists($requestedScope)) { - $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); - - return null; - } - } - } elseif ($availableScope) { - // use the scope associated with this grant type - $requestedScope = $availableScope; - } else { - // use a globally-defined default scope - $defaultScope = $this->scopeUtil->getDefaultScope($clientId); - - // "false" means default scopes are not allowed - if (false === $defaultScope) { - $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter'); - - return null; - } - - $requestedScope = $defaultScope; - } - - return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); - } - - /** - * addGrantType - * - * @param grantType - OAuth2\GrantTypeInterface - * the grant type to add for the specified identifier - * @param identifier - string - * a string passed in as "grant_type" in the response that will call this grantType - */ - public function addGrantType(GrantTypeInterface $grantType, $identifier = null) - { - if (is_null($identifier) || is_numeric($identifier)) { - $identifier = $grantType->getQuerystringIdentifier(); - } - - $this->grantTypes[$identifier] = $grantType; - } - - public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response) - { - if ($this->revokeToken($request, $response)) { - $response->setStatusCode(200); - $response->addParameters(array('revoked' => true)); - } - } - - /** - * Revoke a refresh or access token. Returns true on success and when tokens are invalid - * - * Note: invalid tokens do not cause an error response since the client - * cannot handle such an error in a reasonable way. Moreover, the - * purpose of the revocation request, invalidating the particular token, - * is already achieved. - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool|null - */ - public function revokeToken(RequestInterface $request, ResponseInterface $response) - { - if (strtolower($request->server('REQUEST_METHOD')) != 'post') { - $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2'); - $response->addHttpHeaders(array('Allow' => 'POST')); - - return null; - } - - $token_type_hint = $request->request('token_type_hint'); - if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) { - $response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\''); - - return null; - } - - $token = $request->request('token'); - if ($token === null) { - $response->setError(400, 'invalid_request', 'Missing token parameter to revoke'); - - return null; - } - - // @todo remove this check for v2.0 - if (!method_exists($this->accessToken, 'revokeToken')) { - $class = get_class($this->accessToken); - throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method"); - } - - $this->accessToken->revokeToken($token, $token_type_hint); - - return true; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php b/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php deleted file mode 100644 index 72d72570f..000000000 --- a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - $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/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php b/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php deleted file mode 100644 index 2d336c664..000000000 --- a/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php +++ /dev/null @@ -1,11 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Encryption/Jwt.php b/library/oauth2/src/OAuth2/Encryption/Jwt.php deleted file mode 100644 index ee576e643..000000000 --- a/library/oauth2/src/OAuth2/Encryption/Jwt.php +++ /dev/null @@ -1,173 +0,0 @@ -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/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php deleted file mode 100644 index e8995204c..000000000 --- a/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php +++ /dev/null @@ -1,100 +0,0 @@ - - */ -class AuthorizationCode implements GrantTypeInterface -{ - protected $storage; - protected $authCode; - - /** - * @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information - */ - public function __construct(AuthorizationCodeInterface $storage) - { - $this->storage = $storage; - } - - public function getQuerystringIdentifier() - { - return 'authorization_code'; - } - - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$request->request('code')) { - $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); - - return false; - } - - $code = $request->request('code'); - if (!$authCode = $this->storage->getAuthorizationCode($code)) { - $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client'); - - return false; - } - - /* - * 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request - * @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3 - */ - if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) { - if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) { - $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3"); - - return false; - } - } - - if (!isset($authCode['expires'])) { - throw new \Exception('Storage must return authcode with a value for "expires"'); - } - - if ($authCode["expires"] < time()) { - $response->setError(400, 'invalid_grant', "The authorization code has expired"); - - return false; - } - - if (!isset($authCode['code'])) { - $authCode['code'] = $code; // used to expire the code after the access token is granted - } - - $this->authCode = $authCode; - - return true; - } - - public function getClientId() - { - return $this->authCode['client_id']; - } - - public function getScope() - { - return isset($this->authCode['scope']) ? $this->authCode['scope'] : null; - } - - public function getUserId() - { - return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null; - } - - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - $token = $accessToken->createAccessToken($client_id, $user_id, $scope); - $this->storage->expireAuthorizationCode($this->authCode['code']); - - return $token; - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php b/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php deleted file mode 100644 index f953e4e8d..000000000 --- a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php +++ /dev/null @@ -1,67 +0,0 @@ - - * - * @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/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php b/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php deleted file mode 100644 index 98489e9c1..000000000 --- a/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/GrantType/RefreshToken.php b/library/oauth2/src/OAuth2/GrantType/RefreshToken.php deleted file mode 100644 index e55385222..000000000 --- a/library/oauth2/src/OAuth2/GrantType/RefreshToken.php +++ /dev/null @@ -1,111 +0,0 @@ - - */ -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 - * - * $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 - * ); - * - */ - 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/library/oauth2/src/OAuth2/GrantType/UserCredentials.php b/library/oauth2/src/OAuth2/GrantType/UserCredentials.php deleted file mode 100644 index f165538ba..000000000 --- a/library/oauth2/src/OAuth2/GrantType/UserCredentials.php +++ /dev/null @@ -1,83 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php deleted file mode 100644 index c9b5c6af7..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php +++ /dev/null @@ -1,106 +0,0 @@ -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/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php deleted file mode 100644 index 1e231d844..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -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/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php deleted file mode 100644 index a89049d49..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - $response = new OAuth2\Response(); - * > $userInfoController->handleUserInfoRequest( - * > OAuth2\Request::createFromGlobals(), - * > $response; - * > $response->send(); - * - */ -interface UserInfoControllerInterface -{ - public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php deleted file mode 100644 index 8ed1edc26..000000000 --- a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php deleted file mode 100644 index 8971954c5..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php deleted file mode 100644 index ea4779255..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php deleted file mode 100644 index ac7764d6c..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php +++ /dev/null @@ -1,24 +0,0 @@ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php deleted file mode 100644 index 629adcca8..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php deleted file mode 100644 index 0bd2f8391..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php +++ /dev/null @@ -1,29 +0,0 @@ -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/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php deleted file mode 100644 index ac13e2032..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php +++ /dev/null @@ -1,9 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php b/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php deleted file mode 100644 index f230bef9e..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php +++ /dev/null @@ -1,38 +0,0 @@ - value format. - * - * @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims - */ - public function getUserClaims($user_id, $scope); -} diff --git a/library/oauth2/src/OAuth2/Request.php b/library/oauth2/src/OAuth2/Request.php deleted file mode 100644 index c92cee821..000000000 --- a/library/oauth2/src/OAuth2/Request.php +++ /dev/null @@ -1,213 +0,0 @@ -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/library/oauth2/src/OAuth2/RequestInterface.php b/library/oauth2/src/OAuth2/RequestInterface.php deleted file mode 100644 index 8a70d5fad..000000000 --- a/library/oauth2/src/OAuth2/RequestInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 418 => 'I\'m a teapot', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - ); - - public function __construct($parameters = array(), $statusCode = 200, $headers = array()) - { - $this->setParameters($parameters); - $this->setStatusCode($statusCode); - $this->setHttpHeaders($headers); - $this->version = '1.1'; - } - - /** - * Converts the response object to string containing all headers and the response content. - * - * @return string The response with headers and content - */ - public function __toString() - { - $headers = array(); - foreach ($this->httpHeaders as $name => $value) { - $headers[$name] = (array) $value; - } - - return - sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". - $this->getHttpHeadersAsString($headers)."\r\n". - $this->getResponseBody(); - } - - /** - * Returns the build header line. - * - * @param string $name The header name - * @param string $value The header value - * - * @return string The built header line - */ - protected function buildHeader($name, $value) - { - return sprintf("%s: %s\n", $name, $value); - } - - public function getStatusCode() - { - return $this->statusCode; - } - - public function setStatusCode($statusCode, $text = null) - { - $this->statusCode = (int) $statusCode; - if ($this->isInvalid()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode)); - } - - $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text); - } - - public function getStatusText() - { - return $this->statusText; - } - - public function getParameters() - { - return $this->parameters; - } - - public function setParameters(array $parameters) - { - $this->parameters = $parameters; - } - - public function addParameters(array $parameters) - { - $this->parameters = array_merge($this->parameters, $parameters); - } - - public function getParameter($name, $default = null) - { - return isset($this->parameters[$name]) ? $this->parameters[$name] : $default; - } - - public function setParameter($name, $value) - { - $this->parameters[$name] = $value; - } - - public function setHttpHeaders(array $httpHeaders) - { - $this->httpHeaders = $httpHeaders; - } - - public function setHttpHeader($name, $value) - { - $this->httpHeaders[$name] = $value; - } - - public function addHttpHeaders(array $httpHeaders) - { - $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders); - } - - public function getHttpHeaders() - { - return $this->httpHeaders; - } - - public function getHttpHeader($name, $default = null) - { - return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default; - } - - public function getResponseBody($format = 'json') - { - switch ($format) { - case 'json': - return json_encode($this->parameters); - case 'xml': - // this only works for single-level arrays - $xml = new \SimpleXMLElement(''); - 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/library/oauth2/src/OAuth2/ResponseInterface.php b/library/oauth2/src/OAuth2/ResponseInterface.php deleted file mode 100644 index c99b5f7d1..000000000 --- a/library/oauth2/src/OAuth2/ResponseInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ -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 - * - * $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 - * ); - * - */ - public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array()) - { - $this->tokenStorage = $tokenStorage; - $this->refreshStorage = $refreshStorage; - - $this->config = array_merge(array( - 'token_type' => 'bearer', - 'access_lifetime' => 3600, - 'refresh_token_lifetime' => 1209600, - ), $config); - } - - public function getAuthorizeResponse($params, $user_id = null) - { - // build the URL to redirect to - $result = array('query' => array()); - - $params += array('scope' => null, 'state' => null); - - /* - * a refresh token MUST NOT be included in the fragment - * - * @see http://tools.ietf.org/html/rfc6749#section-4.2.2 - */ - $includeRefreshToken = false; - $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken); - - if (isset($params['state'])) { - $result["fragment"]["state"] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - /** - * Handle the creation of access token, also issue refresh token if supported / desirable. - * - * @param $client_id client identifier related to the access token. - * @param $user_id user ID associated with the access token - * @param $scope OPTIONAL scopes to be stored in space-separated string. - * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response - * - * @see http://tools.ietf.org/html/rfc6749#section-5 - * @ingroup oauth2_section_5 - */ - public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) - { - $token = array( - "access_token" => $this->generateAccessToken(), - "expires_in" => $this->config['access_lifetime'], - "token_type" => $this->config['token_type'], - "scope" => $scope - ); - - $this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); - - /* - * Issue a refresh token also, if we support them - * - * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface - * is supplied in the constructor - */ - if ($includeRefreshToken && $this->refreshStorage) { - $token["refresh_token"] = $this->generateRefreshToken(); - $expires = 0; - if ($this->config['refresh_token_lifetime'] > 0) { - $expires = time() + $this->config['refresh_token_lifetime']; - } - $this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope); - } - - return $token; - } - - /** - * Generates an unique access token. - * - * Implementing classes may want to override this function to implement - * other access token generation schemes. - * - * @return - * An unique access token. - * - * @ingroup oauth2_section_4 - */ - protected function generateAccessToken() - { - if (function_exists('mcrypt_create_iv')) { - $randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - if (function_exists('openssl_random_pseudo_bytes')) { - $randomData = openssl_random_pseudo_bytes(20); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data - $randomData = file_get_contents('/dev/urandom', false, null, 0, 20); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - // Last resort which you probably should just get rid of: - $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); - - return substr(hash('sha512', $randomData), 0, 40); - } - - /** - * Generates an unique refresh token - * - * Implementing classes may want to override this function to implement - * other refresh token generation schemes. - * - * @return - * An unique refresh. - * - * @ingroup oauth2_section_4 - * @see OAuth2::generateAccessToken() - */ - protected function generateRefreshToken() - { - return $this->generateAccessToken(); // let's reuse the same scheme for token generation - } - - /** - * Handle the revoking of refresh tokens, and access tokens if supported / desirable - * RFC7009 specifies that "If the server is unable to locate the token using - * the given hint, it MUST extend its search across all of its supported token types" - * - * @param $token - * @param null $tokenTypeHint - * @return boolean - */ - public function revokeToken($token, $tokenTypeHint = null) - { - if ($tokenTypeHint == 'refresh_token') { - if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) { - return true; - } - } - - /** @TODO remove in v2 */ - if (!method_exists($this->tokenStorage, 'unsetAccessToken')) { - throw new \RuntimeException( - sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage) - )); - } - - $revoked = $this->tokenStorage->unsetAccessToken($token); - - // if a typehint is supplied and fails, try other storages - // @see https://tools.ietf.org/html/rfc7009#section-2.1 - if (!$revoked && $tokenTypeHint != 'refresh_token') { - if ($this->refreshStorage) { - $revoked = $this->refreshStorage->unsetRefreshToken($token); - } - } - - return $revoked; - } -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php b/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php deleted file mode 100644 index 4bd3928d8..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php deleted file mode 100644 index 6a305fd75..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php +++ /dev/null @@ -1,100 +0,0 @@ - - */ -class AuthorizationCode implements AuthorizationCodeInterface -{ - protected $storage; - protected $config; - - public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) - { - $this->storage = $storage; - $this->config = array_merge(array( - 'enforce_redirect' => false, - 'auth_code_lifetime' => 30, - ), $config); - } - - public function getAuthorizeResponse($params, $user_id = null) - { - // build the URL to redirect to - $result = array('query' => array()); - - $params += array('scope' => null, 'state' => null); - - $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']); - - if (isset($params['state'])) { - $result['query']['state'] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - /** - * Handle the creation of the authorization code. - * - * @param $client_id - * Client identifier related to the authorization code - * @param $user_id - * User ID associated with the authorization code - * @param $redirect_uri - * An absolute URI to which the authorization server will redirect the - * user-agent to when the end-user authorization step is completed. - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @ingroup oauth2_section_4 - */ - public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null) - { - $code = $this->generateAuthorizationCode(); - $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope); - - return $code; - } - - /** - * @return - * TRUE if the grant type requires a redirect_uri, FALSE if not - */ - public function enforceRedirect() - { - return $this->config['enforce_redirect']; - } - - /** - * Generates an unique auth code. - * - * Implementing classes may want to override this function to implement - * other auth code generation schemes. - * - * @return - * An unique auth code. - * - * @ingroup oauth2_section_4 - */ - protected function generateAuthorizationCode() - { - $tokenLen = 40; - if (function_exists('mcrypt_create_iv')) { - $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM); - } elseif (function_exists('openssl_random_pseudo_bytes')) { - $randomData = openssl_random_pseudo_bytes(100); - } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data - $randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true); - } else { - $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); - } - - return substr(hash('sha512', $randomData), 0, $tokenLen); - } -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php deleted file mode 100644 index df777e221..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php b/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php deleted file mode 100644 index 3942fe41e..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php +++ /dev/null @@ -1,124 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php b/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php deleted file mode 100644 index f8e26a5b0..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php +++ /dev/null @@ -1,8 +0,0 @@ -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/library/oauth2/src/OAuth2/ScopeInterface.php b/library/oauth2/src/OAuth2/ScopeInterface.php deleted file mode 100644 index 5b60f9aee..000000000 --- a/library/oauth2/src/OAuth2/ScopeInterface.php +++ /dev/null @@ -1,40 +0,0 @@ - 'OAuth2\Storage\AccessTokenInterface', - 'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface', - 'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface', - 'client' => 'OAuth2\Storage\ClientInterface', - 'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface', - 'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface', - 'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface', - 'public_key' => 'OAuth2\Storage\PublicKeyInterface', - 'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface', - 'scope' => 'OAuth2\Storage\ScopeInterface', - ); - - protected $responseTypeMap = array( - 'token' => 'OAuth2\ResponseType\AccessTokenInterface', - 'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface', - 'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface', - 'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface', - 'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface', - ); - - /** - * @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the - * required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum) - * @param array $config specify a different token lifetime, token header name, etc - * @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens - * @param array $responseTypes Response types to use. array keys should be "code" and and "token" for - * Access Token and Authorization Code response types - * @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac" - * @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope - * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic - * - * @ingroup oauth2_section_7 - */ - public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null) - { - $storage = is_array($storage) ? $storage : array($storage); - $this->storages = array(); - foreach ($storage as $key => $service) { - $this->addStorage($service, $key); - } - - // merge all config values. These get passed to our controller objects - $this->config = array_merge(array( - 'use_jwt_access_tokens' => false, - 'store_encrypted_token_string' => true, - 'use_openid_connect' => false, - 'id_lifetime' => 3600, - 'access_lifetime' => 3600, - 'www_realm' => 'Service', - 'token_param_name' => 'access_token', - 'token_bearer_header_name' => 'Bearer', - 'enforce_state' => true, - 'require_exact_redirect_uri' => true, - 'allow_implicit' => false, - 'allow_credentials_in_request_body' => true, - 'allow_public_clients' => true, - 'always_issue_new_refresh_token' => false, - 'unset_refresh_token_after_use' => true, - ), $config); - - foreach ($grantTypes as $key => $grantType) { - $this->addGrantType($grantType, $key); - } - - foreach ($responseTypes as $key => $responseType) { - $this->addResponseType($responseType, $key); - } - - $this->tokenType = $tokenType; - $this->scopeUtil = $scopeUtil; - $this->clientAssertionType = $clientAssertionType; - - if ($this->config['use_openid_connect']) { - $this->validateOpenIdConnect(); - } - } - - public function getAuthorizeController() - { - if (is_null($this->authorizeController)) { - $this->authorizeController = $this->createDefaultAuthorizeController(); - } - - return $this->authorizeController; - } - - public function getTokenController() - { - if (is_null($this->tokenController)) { - $this->tokenController = $this->createDefaultTokenController(); - } - - return $this->tokenController; - } - - public function getResourceController() - { - if (is_null($this->resourceController)) { - $this->resourceController = $this->createDefaultResourceController(); - } - - return $this->resourceController; - } - - public function getUserInfoController() - { - if (is_null($this->userInfoController)) { - $this->userInfoController = $this->createDefaultUserInfoController(); - } - - return $this->userInfoController; - } - - /** - * every getter deserves a setter - */ - public function setAuthorizeController(AuthorizeControllerInterface $authorizeController) - { - $this->authorizeController = $authorizeController; - } - - /** - * every getter deserves a setter - */ - public function setTokenController(TokenControllerInterface $tokenController) - { - $this->tokenController = $tokenController; - } - - /** - * every getter deserves a setter - */ - public function setResourceController(ResourceControllerInterface $resourceController) - { - $this->resourceController = $resourceController; - } - - /** - * every getter deserves a setter - */ - public function setUserInfoController(UserInfoControllerInterface $userInfoController) - { - $this->userInfoController = $userInfoController; - } - - /** - * Return claims about the authenticated end-user. - * This would be called from the "/UserInfo" endpoint as defined in the spec. - * - * @param $request - OAuth2\RequestInterface - * Request object to grant access token - * - * @param $response - OAuth2\ResponseInterface - * Response object containing error messages (failure) or user claims (success) - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo - */ - public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getUserInfoController()->handleUserInfoRequest($request, $this->response); - - return $this->response; - } - - /** - * Grant or deny a requested access token. - * This would be called from the "/token" endpoint as defined in the spec. - * Obviously, you can call your endpoint whatever you want. - * - * @param $request - OAuth2\RequestInterface - * Request object to grant access token - * - * @param $response - OAuth2\ResponseInterface - * Response object containing error messages (failure) or access token (success) - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @see http://tools.ietf.org/html/rfc6749#section-10.6 - * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 - * - * @ingroup oauth2_section_4 - */ - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getTokenController()->handleTokenRequest($request, $this->response); - - return $this->response; - } - - public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getTokenController()->grantAccessToken($request, $this->response); - - return $value; - } - - /** - * Handle a revoke token request - * This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec - * - * @see https://tools.ietf.org/html/rfc7009#section-2 - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return Response|ResponseInterface - */ - public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getTokenController()->handleRevokeRequest($request, $this->response); - - return $this->response; - } - - /** - * Redirect the user appropriately after approval. - * - * After the user has approved or denied the resource request the - * authorization server should call this function to redirect the user - * appropriately. - * - * @param $request - * The request should have the follow parameters set in the querystring: - * - response_type: The requested response: an access token, an - * authorization code, or both. - * - client_id: The client identifier as described in Section 2. - * - redirect_uri: An absolute URI to which the authorization server - * will redirect the user-agent to when the end-user authorization - * step is completed. - * - scope: (optional) The scope of the resource request expressed as a - * list of space-delimited strings. - * - state: (optional) An opaque value used by the client to maintain - * state between the request and callback. - * @param $is_authorized - * TRUE or FALSE depending on whether the user authorized the access. - * @param $user_id - * Identifier of user who authorized the client - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * - * @ingroup oauth2_section_4 - */ - public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) - { - $this->response = $response; - $this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id); - - return $this->response; - } - - /** - * Pull the authorization request data out of the HTTP request. - * - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it - * by setting $config['enforce_redirect'] to true. - * - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that - * CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true. - * - * The draft specifies that the parameters should be retrieved from GET, override the Response - * object to change this - * - * @return - * The authorization parameters so the authorization server can prompt - * the user for approval if valid. - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1.1 - * @see http://tools.ietf.org/html/rfc6749#section-10.12 - * - * @ingroup oauth2_section_3 - */ - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response); - - return $value; - } - - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope); - - return $value; - } - - public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getResourceController()->getAccessTokenData($request, $this->response); - - return $value; - } - - public function addGrantType(GrantTypeInterface $grantType, $identifier = null) - { - if (!is_string($identifier)) { - $identifier = $grantType->getQuerystringIdentifier(); - } - - $this->grantTypes[$identifier] = $grantType; - - // persist added grant type down to TokenController - if (!is_null($this->tokenController)) { - $this->getTokenController()->addGrantType($grantType, $identifier); - } - } - - /** - * Set a storage object for the server - * - * @param $storage - * An object implementing one of the Storage interfaces - * @param $key - * If null, the storage is set to the key of each storage interface it implements - * - * @see storageMap - */ - public function addStorage($storage, $key = null) - { - // if explicitly set to a valid key, do not "magically" set below - if (isset($this->storageMap[$key])) { - if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) { - throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key])); - } - $this->storages[$key] = $storage; - - // special logic to handle "client" and "client_credentials" strangeness - if ($key === 'client' && !isset($this->storages['client_credentials'])) { - if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) { - $this->storages['client_credentials'] = $storage; - } - } elseif ($key === 'client_credentials' && !isset($this->storages['client'])) { - if ($storage instanceof \OAuth2\Storage\ClientInterface) { - $this->storages['client'] = $storage; - } - } - } elseif (!is_null($key) && !is_numeric($key)) { - throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap)))); - } else { - $set = false; - foreach ($this->storageMap as $type => $interface) { - if ($storage instanceof $interface) { - $this->storages[$type] = $storage; - $set = true; - } - } - - if (!$set) { - throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap))); - } - } - } - - public function addResponseType(ResponseTypeInterface $responseType, $key = null) - { - $key = $this->normalizeResponseType($key); - - if (isset($this->responseTypeMap[$key])) { - if (!$responseType instanceof $this->responseTypeMap[$key]) { - throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key])); - } - $this->responseTypes[$key] = $responseType; - } elseif (!is_null($key) && !is_numeric($key)) { - throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap)))); - } else { - $set = false; - foreach ($this->responseTypeMap as $type => $interface) { - if ($responseType instanceof $interface) { - $this->responseTypes[$type] = $responseType; - $set = true; - } - } - - if (!$set) { - throw new \InvalidArgumentException(sprintf('Unknown response type %s. Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap))); - } - } - } - - public function getScopeUtil() - { - if (!$this->scopeUtil) { - $storage = isset($this->storages['scope']) ? $this->storages['scope'] : null; - $this->scopeUtil = new Scope($storage); - } - - return $this->scopeUtil; - } - - /** - * every getter deserves a setter - */ - public function setScopeUtil($scopeUtil) - { - $this->scopeUtil = $scopeUtil; - } - - protected function createDefaultAuthorizeController() - { - if (!isset($this->storages['client'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server"); - } - if (0 == count($this->responseTypes)) { - $this->responseTypes = $this->getDefaultResponseTypes(); - } - if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) { - $this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType(); - if ($this->config['allow_implicit']) { - $this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType(); - } - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri'))); - - if ($this->config['use_openid_connect']) { - return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); - } - - return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); - } - - protected function createDefaultTokenController() - { - if (0 == count($this->grantTypes)) { - $this->grantTypes = $this->getDefaultGrantTypes(); - } - - if (is_null($this->clientAssertionType)) { - // see if HttpBasic assertion type is requred. If so, then create it from storage classes. - foreach ($this->grantTypes as $grantType) { - if (!$grantType instanceof ClientAssertionTypeInterface) { - if (!isset($this->storages['client_credentials'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server"); - } - $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients'))); - $this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config); - break; - } - } - } - - if (!isset($this->storages['client'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server"); - } - - $accessTokenResponseType = $this->getAccessTokenResponseType(); - - return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil()); - } - - protected function createDefaultResourceController() - { - if ($this->config['use_jwt_access_tokens']) { - // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set - if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { - $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); - } - } elseif (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server"); - } - - if (!$this->tokenType) { - $this->tokenType = $this->getDefaultTokenType(); - } - - $config = array_intersect_key($this->config, array('www_realm' => '')); - - return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil()); - } - - protected function createDefaultUserInfoController() - { - if ($this->config['use_jwt_access_tokens']) { - // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set - if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { - $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); - } - } elseif (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server"); - } - - if (!isset($this->storages['user_claims'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server"); - } - - if (!$this->tokenType) { - $this->tokenType = $this->getDefaultTokenType(); - } - - $config = array_intersect_key($this->config, array('www_realm' => '')); - - return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil()); - } - - protected function getDefaultTokenType() - { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name'))); - - return new Bearer($config); - } - - protected function getDefaultResponseTypes() - { - $responseTypes = array(); - - if ($this->config['allow_implicit']) { - $responseTypes['token'] = $this->getAccessTokenResponseType(); - } - - if ($this->config['use_openid_connect']) { - $responseTypes['id_token'] = $this->getIdTokenResponseType(); - if ($this->config['allow_implicit']) { - $responseTypes['id_token token'] = $this->getIdTokenTokenResponseType(); - } - } - - if (isset($this->storages['authorization_code'])) { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime'))); - if ($this->config['use_openid_connect']) { - if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { - throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); - } - $responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config); - $responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']); - } else { - $responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config); - } - } - - if (count($responseTypes) == 0) { - throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object"); - } - - return $responseTypes; - } - - protected function getDefaultGrantTypes() - { - $grantTypes = array(); - - if (isset($this->storages['user_credentials'])) { - $grantTypes['password'] = new UserCredentials($this->storages['user_credentials']); - } - - if (isset($this->storages['client_credentials'])) { - $config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => '')); - $grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config); - } - - if (isset($this->storages['refresh_token'])) { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use'))); - $grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config); - } - - if (isset($this->storages['authorization_code'])) { - if ($this->config['use_openid_connect']) { - if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { - throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); - } - $grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']); - } else { - $grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']); - } - } - - if (count($grantTypes) == 0) { - throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor"); - } - - return $grantTypes; - } - - protected function getAccessTokenResponseType() - { - if (isset($this->responseTypes['token'])) { - return $this->responseTypes['token']; - } - - if ($this->config['use_jwt_access_tokens']) { - return $this->createDefaultJwtAccessTokenResponseType(); - } - - return $this->createDefaultAccessTokenResponseType(); - } - - protected function getIdTokenResponseType() - { - if (isset($this->responseTypes['id_token'])) { - return $this->responseTypes['id_token']; - } - - return $this->createDefaultIdTokenResponseType(); - } - - protected function getIdTokenTokenResponseType() - { - if (isset($this->responseTypes['id_token token'])) { - return $this->responseTypes['id_token token']; - } - - return $this->createDefaultIdTokenTokenResponseType(); - } - - /** - * For Resource Controller - */ - protected function createDefaultJwtAccessTokenStorage() - { - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); - } - $tokenStorage = null; - if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) { - $tokenStorage = $this->storages['access_token']; - } - // wrap the access token storage as required. - return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage); - } - - /** - * For Authorize and Token Controllers - */ - protected function createDefaultJwtAccessTokenResponseType() - { - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); - } - - $tokenStorage = null; - if (isset($this->storages['access_token'])) { - $tokenStorage = $this->storages['access_token']; - } - - $refreshStorage = null; - if (isset($this->storages['refresh_token'])) { - $refreshStorage = $this->storages['refresh_token']; - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime'))); - - return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config); - } - - protected function createDefaultAccessTokenResponseType() - { - if (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server"); - } - - $refreshStorage = null; - if (isset($this->storages['refresh_token'])) { - $refreshStorage = $this->storages['refresh_token']; - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime'))); - $config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() : $this->getDefaultTokenType()->getTokenType(); - - return new AccessToken($this->storages['access_token'], $refreshStorage, $config); - } - - protected function createDefaultIdTokenResponseType() - { - if (!isset($this->storages['user_claims'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect"); - } - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect"); - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime'))); - - return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config); - } - - protected function createDefaultIdTokenTokenResponseType() - { - return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType()); - } - - protected function validateOpenIdConnect() - { - $authCodeGrant = $this->getGrantType('authorization_code'); - if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) { - throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.'); - } - } - - protected function normalizeResponseType($name) - { - // for multiple-valued response types - make them alphabetical - if (!empty($name) && false !== strpos($name, ' ')) { - $types = explode(' ', $name); - sort($types); - $name = implode(' ', $types); - } - - return $name; - } - - public function getResponse() - { - return $this->response; - } - - public function getStorages() - { - return $this->storages; - } - - public function getStorage($name) - { - return isset($this->storages[$name]) ? $this->storages[$name] : null; - } - - public function getGrantTypes() - { - return $this->grantTypes; - } - - public function getGrantType($name) - { - return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null; - } - - public function getResponseTypes() - { - return $this->responseTypes; - } - - public function getResponseType($name) - { - // for multiple-valued response types - make them alphabetical - $name = $this->normalizeResponseType($name); - - return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null; - } - - public function getTokenType() - { - return $this->tokenType; - } - - public function getClientAssertionType() - { - return $this->clientAssertionType; - } - - public function setConfig($name, $value) - { - $this->config[$name] = $value; - } - - public function getConfig($name, $default = null) - { - return isset($this->config[$name]) ? $this->config[$name] : $default; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php deleted file mode 100644 index 1819158af..000000000 --- a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php deleted file mode 100644 index 3beb0e437..000000000 --- a/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php +++ /dev/null @@ -1,86 +0,0 @@ - - */ -interface AuthorizationCodeInterface -{ - /** - * The Authorization Code grant type supports a response type of "code". - * - * @var string - * @see http://tools.ietf.org/html/rfc6749#section-1.4.1 - * @see http://tools.ietf.org/html/rfc6749#section-4.2 - */ - const RESPONSE_TYPE_CODE = "code"; - - /** - * Fetch authorization code data (probably the most common grant type). - * - * Retrieve the stored data for the given authorization code. - * - * Required for OAuth2::GRANT_TYPE_AUTH_CODE. - * - * @param $code - * Authorization code to be check with. - * - * @return - * An associative array as below, and NULL if the code is invalid - * @code - * return array( - * "client_id" => CLIENT_ID, // REQUIRED Stored client identifier - * "user_id" => USER_ID, // REQUIRED Stored user identifier - * "expires" => EXPIRES, // REQUIRED Stored expiration in unix timestamp - * "redirect_uri" => REDIRECT_URI, // REQUIRED Stored redirect URI - * "scope" => SCOPE, // OPTIONAL Stored scope values in space-separated string - * ); - * @endcode - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1 - * - * @ingroup oauth2_section_4 - */ - public function getAuthorizationCode($code); - - /** - * Take the provided authorization code values and store them somewhere. - * - * This function should be the storage counterpart to getAuthCode(). - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * Required for OAuth2::GRANT_TYPE_AUTH_CODE. - * - * @param string $code Authorization code to be stored. - * @param mixed $client_id Client identifier to be stored. - * @param mixed $user_id User identifier to be stored. - * @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string. - * @param int $expires Expiration to be stored as a Unix timestamp. - * @param string $scope OPTIONAL Scopes to be stored in space-separated string. - * - * @ingroup oauth2_section_4 - */ - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null); - - /** - * once an Authorization Code is used, it must be exipired - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1.2 - * - * The client MUST NOT use the authorization code - * more than once. If an authorization code is used more than - * once, the authorization server MUST deny the request and SHOULD - * revoke (when possible) all tokens previously issued based on - * that authorization code - * - */ - public function expireAuthorizationCode($code); -} diff --git a/library/oauth2/src/OAuth2/Storage/Cassandra.php b/library/oauth2/src/OAuth2/Storage/Cassandra.php deleted file mode 100644 index 602e8a058..000000000 --- a/library/oauth2/src/OAuth2/Storage/Cassandra.php +++ /dev/null @@ -1,480 +0,0 @@ - - * composer require thobbs/phpcassa:dev-master - * - * - * Once this is done, instantiate the - * - * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160')); - * - * - * Then, register the storage client: - * - * $storage = new OAuth2\Storage\Cassandra($cassandra); - * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); - * - * - * @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/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php deleted file mode 100644 index 3318c6966..000000000 --- a/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php +++ /dev/null @@ -1,49 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/ClientInterface.php b/library/oauth2/src/OAuth2/Storage/ClientInterface.php deleted file mode 100644 index 09a5bffc1..000000000 --- a/library/oauth2/src/OAuth2/Storage/ClientInterface.php +++ /dev/null @@ -1,66 +0,0 @@ - - */ -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. - * - * 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 - * ); - * - * - * @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/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php b/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php deleted file mode 100755 index 1eb55f027..000000000 --- a/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php +++ /dev/null @@ -1,331 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/DynamoDB.php b/library/oauth2/src/OAuth2/Storage/DynamoDB.php deleted file mode 100644 index 8347ab258..000000000 --- a/library/oauth2/src/OAuth2/Storage/DynamoDB.php +++ /dev/null @@ -1,540 +0,0 @@ - - * composer require aws/aws-sdk-php:dev-master - * - * - * Once this is done, instantiate the DynamoDB client - * - * $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION")); - * - * - * 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 - */ -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/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php b/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php deleted file mode 100644 index 75b49d301..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php +++ /dev/null @@ -1,88 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php deleted file mode 100644 index 3abb2aa2d..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php +++ /dev/null @@ -1,14 +0,0 @@ - - */ -interface JwtAccessTokenInterface extends AccessTokenInterface -{ - -} diff --git a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php b/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php deleted file mode 100644 index c83aa72ea..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php +++ /dev/null @@ -1,74 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/Memory.php b/library/oauth2/src/OAuth2/Storage/Memory.php deleted file mode 100644 index 42d833ccb..000000000 --- a/library/oauth2/src/OAuth2/Storage/Memory.php +++ /dev/null @@ -1,381 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/Mongo.php b/library/oauth2/src/OAuth2/Storage/Mongo.php deleted file mode 100644 index cef35e5e9..000000000 --- a/library/oauth2/src/OAuth2/Storage/Mongo.php +++ /dev/null @@ -1,339 +0,0 @@ - - */ -class Mongo implements AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - OpenIDAuthorizationCodeInterface -{ - protected $db; - protected $config; - - public function __construct($connection, $config = array()) - { - if ($connection instanceof \MongoDB) { - $this->db = $connection; - } else { - if (!is_array($connection)) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array'); - } - $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']); - $m = new \MongoClient($server); - $this->db = $m->{$connection['database']}; - } - - $this->config = array_merge(array( - 'client_table' => 'oauth_clients', - 'access_token_table' => 'oauth_access_tokens', - 'refresh_token_table' => 'oauth_refresh_tokens', - 'code_table' => 'oauth_authorization_codes', - 'user_table' => 'oauth_users', - 'jwt_table' => 'oauth_jwt', - ), $config); - } - - // Helper function to access a MongoDB collection by `type`: - protected function collection($name) - { - return $this->db->{$this->config[$name]}; - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { - return $result['client_secret'] == $client_secret; - } - - return false; - } - - public function isPublicClient($client_id) - { - if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { - return false; - } - - return empty($result['client_secret']); - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - $result = $this->collection('client_table')->findOne(array('client_id' => $client_id)); - - return is_null($result) ? false : $result; - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - if ($this->getClientDetails($client_id)) { - $this->collection('client_table')->update( - array('client_id' => $client_id), - array('$set' => array( - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - )) - ); - } else { - $client = array( - 'client_id' => $client_id, - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - ); - $this->collection('client_table')->insert($client); - } - - return true; - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token)); - - return is_null($token) ? false : $token; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - // if it exists, update it. - if ($this->getAccessToken($access_token)) { - $this->collection('access_token_table')->update( - array('access_token' => $access_token), - array('$set' => array( - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - )) - ); - } else { - $token = array( - 'access_token' => $access_token, - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - ); - $this->collection('access_token_table')->insert($token); - } - - return true; - } - - public function unsetAccessToken($access_token) - { - $result = $this->collection('access_token_table')->remove(array( - 'access_token' => $access_token - ), array('w' => 1)); - - return $result['n'] > 0; - } - - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - $code = $this->collection('code_table')->findOne(array('authorization_code' => $code)); - - return is_null($code) ? false : $code; - } - - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - // if it exists, update it. - if ($this->getAuthorizationCode($code)) { - $this->collection('code_table')->update( - array('authorization_code' => $code), - array('$set' => array( - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - )) - ); - } else { - $token = array( - 'authorization_code' => $code, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - ); - $this->collection('code_table')->insert($token); - } - - return true; - } - - public function expireAuthorizationCode($code) - { - $this->collection('code_table')->remove(array('authorization_code' => $code)); - - return true; - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - public function getUserDetails($username) - { - if ($user = $this->getUser($username)) { - $user['user_id'] = $user['username']; - } - - return $user; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - $token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token)); - - return is_null($token) ? false : $token; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - $token = array( - 'refresh_token' => $refresh_token, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'expires' => $expires, - 'scope' => $scope - ); - $this->collection('refresh_token_table')->insert($token); - - return true; - } - - public function unsetRefreshToken($refresh_token) - { - $result = $this->collection('refresh_token_table')->remove(array( - 'refresh_token' => $refresh_token - ), array('w' => 1)); - - return $result['n'] > 0; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $password; - } - - public function getUser($username) - { - $result = $this->collection('user_table')->findOne(array('username' => $username)); - - return is_null($result) ? false : $result; - } - - public function setUser($username, $password, $firstName = null, $lastName = null) - { - if ($this->getUser($username)) { - $this->collection('user_table')->update( - array('username' => $username), - array('$set' => array( - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - )) - ); - } else { - $user = array( - 'username' => $username, - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - ); - $this->collection('user_table')->insert($user); - } - - return true; - } - - public function getClientKey($client_id, $subject) - { - $result = $this->collection('jwt_table')->findOne(array( - 'client_id' => $client_id, - 'subject' => $subject - )); - - return is_null($result) ? false : $result['key']; - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs mongodb implementation. - throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.'); - } - - public function setJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs mongodb implementation. - throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.'); - } -} diff --git a/library/oauth2/src/OAuth2/Storage/Pdo.php b/library/oauth2/src/OAuth2/Storage/Pdo.php deleted file mode 100644 index ae5107e29..000000000 --- a/library/oauth2/src/OAuth2/Storage/Pdo.php +++ /dev/null @@ -1,553 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php b/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php deleted file mode 100644 index 108418d3a..000000000 --- a/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - - */ -interface PublicKeyInterface -{ - public function getPublicKey($client_id = null); - public function getPrivateKey($client_id = null); - public function getEncryptionAlgorithm($client_id = null); -} diff --git a/library/oauth2/src/OAuth2/Storage/Redis.php b/library/oauth2/src/OAuth2/Storage/Redis.php deleted file mode 100644 index e6294e22d..000000000 --- a/library/oauth2/src/OAuth2/Storage/Redis.php +++ /dev/null @@ -1,321 +0,0 @@ - - * $storage = new OAuth2\Storage\Redis($redis); - * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); - * - */ -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/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php b/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php deleted file mode 100644 index 0273f2125..000000000 --- a/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php +++ /dev/null @@ -1,82 +0,0 @@ - - */ -interface RefreshTokenInterface -{ - /** - * Grant refresh access tokens. - * - * Retrieve the stored data for the given refresh token. - * - * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. - * - * @param $refresh_token - * Refresh token to be check with. - * - * @return - * An associative array as below, and NULL if the refresh_token is - * invalid: - * - refresh_token: Refresh token identifier. - * - client_id: Client identifier. - * - user_id: User identifier. - * - expires: Expiration unix timestamp, or 0 if the token doesn't expire. - * - scope: (optional) Scope values in space-separated string. - * - * @see http://tools.ietf.org/html/rfc6749#section-6 - * - * @ingroup oauth2_section_6 - */ - public function getRefreshToken($refresh_token); - - /** - * Take the provided refresh token values and store them somewhere. - * - * This function should be the storage counterpart to getRefreshToken(). - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. - * - * @param $refresh_token - * Refresh token to be stored. - * @param $client_id - * Client identifier to be stored. - * @param $user_id - * User identifier to be stored. - * @param $expires - * Expiration timestamp to be stored. 0 if the token doesn't expire. - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * - * @ingroup oauth2_section_6 - */ - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null); - - /** - * Expire a used refresh token. - * - * This is not explicitly required in the spec, but is almost implied. - * After granting a new refresh token, the old one is no longer useful and - * so should be forcibly expired in the data store so it can't be used again. - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * @param $refresh_token - * Refresh token to be expirse. - * - * @ingroup oauth2_section_6 - */ - public function unsetRefreshToken($refresh_token); -} diff --git a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php b/library/oauth2/src/OAuth2/Storage/ScopeInterface.php deleted file mode 100644 index a8292269b..000000000 --- a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php +++ /dev/null @@ -1,46 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php deleted file mode 100644 index 6e0fd7bad..000000000 --- a/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php +++ /dev/null @@ -1,52 +0,0 @@ - - */ -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/library/oauth2/src/OAuth2/TokenType/Bearer.php b/library/oauth2/src/OAuth2/TokenType/Bearer.php deleted file mode 100644 index 8ac8596ac..000000000 --- a/library/oauth2/src/OAuth2/TokenType/Bearer.php +++ /dev/null @@ -1,130 +0,0 @@ -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/library/oauth2/src/OAuth2/TokenType/Mac.php b/library/oauth2/src/OAuth2/TokenType/Mac.php deleted file mode 100644 index fe6a86aa6..000000000 --- a/library/oauth2/src/OAuth2/TokenType/Mac.php +++ /dev/null @@ -1,22 +0,0 @@ -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/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php deleted file mode 100644 index 3bfc760e4..000000000 --- a/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php +++ /dev/null @@ -1,492 +0,0 @@ -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/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php b/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php deleted file mode 100644 index ee6d96ff8..000000000 --- a/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php +++ /dev/null @@ -1,175 +0,0 @@ -getTestServer(); - $request = Request::createFromGlobals(); - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - } - - public function testMalformedHeader() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'tH1s i5 B0gU5'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Malformed auth header'); - } - - public function testMultipleTokensSubmitted() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->request['access_token'] = 'TEST'; - $request->query['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); - } - - public function testInvalidRequestMethod() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->server['REQUEST_METHOD'] = 'GET'; - $request->request['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'When putting the token in the body, the method must be POST or PUT'); - } - - public function testInvalidContentType() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->server['REQUEST_METHOD'] = 'POST'; - $request->server['CONTENT_TYPE'] = 'application/json'; - $request->request['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"'); - } - - public function testInvalidToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer TESTTOKEN'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_token'); - $this->assertEquals($response->getParameter('error_description'), 'The access token provided is invalid'); - } - - public function testExpiredToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-expired'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'expired_token'); - $this->assertEquals($response->getParameter('error_description'), 'The access token provided has expired'); - } - - public function testOutOfScopeToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $scope = 'outofscope'; - $allow = $server->verifyResourceRequest($request, $response = new Response(), $scope); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 403); - $this->assertEquals($response->getParameter('error'), 'insufficient_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The request requires higher privileges than provided by the access token'); - - // verify the "scope" has been set in the "WWW-Authenticate" header - preg_match('/scope="(.*?)"/', $response->getHttpHeader('WWW-Authenticate'), $matches); - $this->assertEquals(2, count($matches)); - $this->assertEquals($matches[1], 'outofscope'); - } - - public function testMalformedToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-malformed'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'malformed_token'); - $this->assertEquals($response->getParameter('error_description'), 'Malformed token (missing "expires")'); - } - - public function testValidToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertTrue($allow); - } - - public function testValidTokenWithScopeParam() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $request->query['scope'] = 'testscope'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertTrue($allow); - } - - public function testCreateController() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $tokenType = new \OAuth2\TokenType\Bearer(); - $controller = new ResourceController($tokenType, $storage); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - // Add the two types supported for authorization grant - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php b/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php deleted file mode 100644 index 4a217bd55..000000000 --- a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php +++ /dev/null @@ -1,289 +0,0 @@ -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/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php b/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php deleted file mode 100644 index d34136767..000000000 --- a/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php +++ /dev/null @@ -1,102 +0,0 @@ -privateKey = << $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/library/oauth2/test/OAuth2/Encryption/JwtTest.php b/library/oauth2/test/OAuth2/Encryption/JwtTest.php deleted file mode 100644 index 214eebac8..000000000 --- a/library/oauth2/test/OAuth2/Encryption/JwtTest.php +++ /dev/null @@ -1,102 +0,0 @@ -privateKey = << $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/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php deleted file mode 100644 index 740989635..000000000 --- a/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php +++ /dev/null @@ -1,207 +0,0 @@ -getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "code" is required'); - } - - public function testInvalidCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'InvalidCode', // invalid authorization code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); - } - - public function testCodeCannotBeUsedTwice() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode', // valid code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNotNull($response->getParameter('access_token')); - - // try to use the same code again - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); - } - - public function testExpiredCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-expired', // expired authorization code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'The authorization code has expired'); - } - - public function testValidCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testValidCodeNoScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1 scope2'); - } - - public function testValidCodeSameScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope2 scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope2 scope1'); - } - - public function testValidCodeLessScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidCodeDifferentScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope3', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidCodeInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'invalid-scope', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidClientDifferentCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Some Other Client', // valid client id - 'client_secret' => 'TestSecret3', // valid client secret - 'code' => 'testcode', // valid code - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'authorization_code doesn\'t exist or is invalid for the client'); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php deleted file mode 100644 index f0d46ccb3..000000000 --- a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php +++ /dev/null @@ -1,159 +0,0 @@ -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/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php b/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php deleted file mode 100644 index a47aae3e8..000000000 --- a/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php +++ /dev/null @@ -1,143 +0,0 @@ -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/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php b/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php deleted file mode 100644 index 0a6c4b827..000000000 --- a/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php +++ /dev/null @@ -1,360 +0,0 @@ -privateKey = <<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/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php b/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php deleted file mode 100644 index a458aad8a..000000000 --- a/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php +++ /dev/null @@ -1,204 +0,0 @@ -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/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php deleted file mode 100644 index 18943d055..000000000 --- a/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php +++ /dev/null @@ -1,172 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php deleted file mode 100644 index 46de936d8..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php +++ /dev/null @@ -1,182 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php deleted file mode 100644 index b1b687077..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php +++ /dev/null @@ -1,44 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php deleted file mode 100644 index 776002d1e..000000000 --- a/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php +++ /dev/null @@ -1,57 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php deleted file mode 100644 index b0311434a..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php +++ /dev/null @@ -1,182 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php deleted file mode 100644 index e772f6be4..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php +++ /dev/null @@ -1,184 +0,0 @@ - '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/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php deleted file mode 100644 index bc564d37b..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php +++ /dev/null @@ -1,91 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php deleted file mode 100644 index bdfb085e3..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php +++ /dev/null @@ -1,95 +0,0 @@ -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/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php deleted file mode 100644 index 840f6c566..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php +++ /dev/null @@ -1,41 +0,0 @@ -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/library/oauth2/test/OAuth2/RequestTest.php b/library/oauth2/test/OAuth2/RequestTest.php deleted file mode 100644 index 10db3215c..000000000 --- a/library/oauth2/test/OAuth2/RequestTest.php +++ /dev/null @@ -1,98 +0,0 @@ -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/library/oauth2/test/OAuth2/ResponseTest.php b/library/oauth2/test/OAuth2/ResponseTest.php deleted file mode 100644 index b8149005d..000000000 --- a/library/oauth2/test/OAuth2/ResponseTest.php +++ /dev/null @@ -1,17 +0,0 @@ - 'bar', - 'halland' => 'oates', - )); - - $string = $response->getResponseBody('xml'); - $this->assertContains('baroates', $string); - } -} diff --git a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php deleted file mode 100644 index 0ed1c82fc..000000000 --- a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php +++ /dev/null @@ -1,107 +0,0 @@ - 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/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php deleted file mode 100644 index 51b01a927..000000000 --- a/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php +++ /dev/null @@ -1,160 +0,0 @@ -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/library/oauth2/test/OAuth2/ScopeTest.php b/library/oauth2/test/OAuth2/ScopeTest.php deleted file mode 100644 index 99f9cf6eb..000000000 --- a/library/oauth2/test/OAuth2/ScopeTest.php +++ /dev/null @@ -1,42 +0,0 @@ -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/library/oauth2/test/OAuth2/ServerTest.php b/library/oauth2/test/OAuth2/ServerTest.php deleted file mode 100644 index 747e120f5..000000000 --- a/library/oauth2/test/OAuth2/ServerTest.php +++ /dev/null @@ -1,684 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php deleted file mode 100644 index b34e0bfc0..000000000 --- a/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php +++ /dev/null @@ -1,102 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php deleted file mode 100644 index 2d901b501..000000000 --- a/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php +++ /dev/null @@ -1,106 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php deleted file mode 100644 index 15289af30..000000000 --- a/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php +++ /dev/null @@ -1,28 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/ClientTest.php b/library/oauth2/test/OAuth2/Storage/ClientTest.php deleted file mode 100644 index 6a5cc0b49..000000000 --- a/library/oauth2/test/OAuth2/Storage/ClientTest.php +++ /dev/null @@ -1,110 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php b/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php deleted file mode 100644 index 2147f0914..000000000 --- a/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php +++ /dev/null @@ -1,40 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php deleted file mode 100644 index a6acbea1f..000000000 --- a/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php +++ /dev/null @@ -1,41 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php b/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php deleted file mode 100644 index d0ab9b899..000000000 --- a/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php +++ /dev/null @@ -1,25 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/PdoTest.php b/library/oauth2/test/OAuth2/Storage/PdoTest.php deleted file mode 100644 index 57eb39072..000000000 --- a/library/oauth2/test/OAuth2/Storage/PdoTest.php +++ /dev/null @@ -1,39 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php b/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php deleted file mode 100644 index f85195870..000000000 --- a/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php +++ /dev/null @@ -1,29 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php b/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php deleted file mode 100644 index 314c93195..000000000 --- a/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php +++ /dev/null @@ -1,41 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/ScopeTest.php b/library/oauth2/test/OAuth2/Storage/ScopeTest.php deleted file mode 100644 index fd1edeb93..000000000 --- a/library/oauth2/test/OAuth2/Storage/ScopeTest.php +++ /dev/null @@ -1,53 +0,0 @@ -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/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php deleted file mode 100644 index 65655a6b2..000000000 --- a/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php +++ /dev/null @@ -1,40 +0,0 @@ -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/library/oauth2/test/OAuth2/TokenType/BearerTest.php b/library/oauth2/test/OAuth2/TokenType/BearerTest.php deleted file mode 100644 index a2e000e22..000000000 --- a/library/oauth2/test/OAuth2/TokenType/BearerTest.php +++ /dev/null @@ -1,58 +0,0 @@ - '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/library/oauth2/test/bootstrap.php b/library/oauth2/test/bootstrap.php deleted file mode 100644 index 0a4af0716..000000000 --- a/library/oauth2/test/bootstrap.php +++ /dev/null @@ -1,12 +0,0 @@ -cleanupTravisDynamoDb(); diff --git a/library/oauth2/test/config/keys/id_rsa b/library/oauth2/test/config/keys/id_rsa deleted file mode 100644 index e8b9eff2d..000000000 --- a/library/oauth2/test/config/keys/id_rsa +++ /dev/null @@ -1,15 +0,0 @@ ------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/library/oauth2/test/config/keys/id_rsa.pub b/library/oauth2/test/config/keys/id_rsa.pub deleted file mode 100644 index 1ac15f5eb..000000000 --- a/library/oauth2/test/config/keys/id_rsa.pub +++ /dev/null @@ -1,16 +0,0 @@ ------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/library/oauth2/test/config/storage.json b/library/oauth2/test/config/storage.json deleted file mode 100644 index a31d3bca2..000000000 --- a/library/oauth2/test/config/storage.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "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" - } - }, - "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/library/oauth2/test/lib/OAuth2/Request/TestRequest.php b/library/oauth2/test/lib/OAuth2/Request/TestRequest.php deleted file mode 100644 index 7bbce28a4..000000000 --- a/library/oauth2/test/lib/OAuth2/Request/TestRequest.php +++ /dev/null @@ -1,61 +0,0 @@ -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/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php b/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php deleted file mode 100755 index 921d52500..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php +++ /dev/null @@ -1,34 +0,0 @@ -getMemoryStorage(); - $sqlite = Bootstrap::getInstance()->getSqlitePdo(); - $mysql = Bootstrap::getInstance()->getMysqlPdo(); - $postgres = Bootstrap::getInstance()->getPostgresPdo(); - $mongo = Bootstrap::getInstance()->getMongo(); - $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($redis), - array($cassandra), - array($dynamodb), - array($couchbase), - ); - } -} diff --git a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php b/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php deleted file mode 100755 index 4ac9022b1..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php +++ /dev/null @@ -1,888 +0,0 @@ -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) { - $skipMongo = $this->getEnvVar('SKIP_MONGO_TESTS'); - if (!$skipMongo && class_exists('MongoClient')) { - $mongo = new \MongoClient('mongodb://localhost:27017', array('connect' => false)); - if ($this->testMongoConnection($mongo)) { - $db = $mongo->oauth2_server_php; - $this->removeMongoDb($db); - $this->createMongoDb($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; - } - - private function testMongoConnection(\MongoClient $mongo) - { - try { - $mongo->connect(); - } catch (\MongoConnectionException $e) { - return false; - } - - 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 createMongoDb(\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_jwt->insert(array( - 'client_id' => 'oauth_test_client', - 'key' => $this->getTestPublicKey(), - 'subject' => 'test_subject', - )); - } - - 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 removeMongoDb(\MongoDB $db) - { - $db->drop(); - } - - 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/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php b/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php deleted file mode 100644 index 6caa62068..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php +++ /dev/null @@ -1,32 +0,0 @@ -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/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 @@ + + * @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 @@ + + */ +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 + * + * $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 + * ); + * + */ + 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 @@ + + * $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 + * ); + * + * @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 @@ + $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 @@ +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 @@ + 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 @@ +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 @@ + $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 @@ + + */ +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 @@ +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 @@ + + */ +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 @@ + + * + * @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 @@ + + */ +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 @@ + + */ +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 + * + * $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 + * ); + * + */ + 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 @@ + + */ +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 @@ +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 @@ +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 @@ + $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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ +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 @@ +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 @@ +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 @@ + + */ +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 @@ + 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 @@ +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 @@ + '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(''); + 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 @@ + + */ +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 + * + * $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 + * ); + * + */ + 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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ +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 @@ + '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 @@ + + */ +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 @@ + + */ +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 @@ + + * composer require thobbs/phpcassa:dev-master + * + * + * Once this is done, instantiate the + * + * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160')); + * + * + * Then, register the storage client: + * + * $storage = new OAuth2\Storage\Cassandra($cassandra); + * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); + * + * + * @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 @@ + + */ +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 @@ + + */ +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. + * + * 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 + * ); + * + * + * @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 @@ + + */ +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 @@ + + * composer require aws/aws-sdk-php:dev-master + * + * + * Once this is done, instantiate the DynamoDB client + * + * $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION")); + * + * + * 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 + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + * $storage = new OAuth2\Storage\Redis($redis); + * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); + * + */ +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 @@ + + */ +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 @@ + + */ +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 @@ + + */ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +privateKey = << $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 @@ +privateKey = << $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 @@ +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 @@ +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 @@ +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 @@ +privateKey = <<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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + '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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + 'bar', + 'halland' => 'oates', + )); + + $string = $response->getResponseBody('xml'); + $this->assertContains('baroates', $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 @@ + 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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + '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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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() { @@ -272,26 +271,6 @@ class ClassLoader return $this->classMapAuthoritative; } - /** - * 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. * @@ -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 +Source: https://github.com/composer/composer -Copyright (c) 2016 Nils Adermann, Jordi Boggiano +Files: * +Copyright: 2016, Nils Adermann + 2016, Jordi Boggiano +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 + 2016, Jordi Boggiano + 2013, Evan Coury +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 2adb2fe53..7a91153b0 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,623 +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', - 'Test\\Markdownify\\ConverterExtraTest' => $vendorDir . '/pixel418/markdownify/test/ConverterExtraTest.php', - 'Test\\Markdownify\\ConverterTest' => $vendorDir . '/pixel418/markdownify/test/ConverterTest.php', - 'Test\\Markdownify\\ConverterTestCase' => $vendorDir . '/pixel418/markdownify/test/ConverterTestCase.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..a03d306b4 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -21,7 +21,7 @@ "phpunit/phpunit": "*", "sabre/cs": "~0.0.1" }, - "time": "2016-03-08T02:29:27+00:00", + "time": "2016-03-08 02:29:27", "type": "library", "installation-source": "dist", "autoload": { @@ -79,7 +79,7 @@ "suggest": { "hoa/bench": "If you would like to run the benchmark scripts" }, - "time": "2016-07-15T19:52:17+00:00", + "time": "2016-07-15 19:52:17", "bin": [ "bin/vobject", "bin/generate_vcards" @@ -173,7 +173,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": { @@ -238,7 +238,7 @@ "suggest": { "ext-curl": " to make http requests with the Client class" }, - "time": "2016-01-06T23:00:08+00:00", + "time": "2016-01-06 23:00:08", "type": "library", "installation-source": "dist", "autoload": { @@ -310,7 +310,7 @@ "ext-curl": "*", "ext-pdo": "*" }, - "time": "2016-06-28T02:44:05+00:00", + "time": "2016-06-28 02:44:05", "bin": [ "bin/sabredav", "bin/naturalselection" @@ -379,7 +379,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 +435,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 +484,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 +540,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 +576,63 @@ "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" + ] } ] -- cgit v1.2.3