diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/OAuth2/Controller/AuthorizeControllerTest.php | 6 | ||||
| -rw-r--r-- | test/OAuth2/Controller/ResourceControllerTest.php | 4 | ||||
| -rw-r--r-- | test/OAuth2/Controller/TokenControllerTest.php | 2 | ||||
| -rw-r--r-- | test/OAuth2/GrantType/UserCredentialsTest.php | 1 | ||||
| -rw-r--r-- | test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php | 156 | ||||
| -rw-r--r-- | test/OAuth2/OpenID/Controller/UserInfoControllerTest.php | 14 | ||||
| -rw-r--r-- | test/OAuth2/OpenID/ResponseType/TokenIdTokenTest.php | 2 | ||||
| -rw-r--r-- | test/OAuth2/ResponseTest.php | 2 | ||||
| -rw-r--r-- | test/OAuth2/ResponseType/CryptoTokenTest.php | 43 | ||||
| -rw-r--r-- | test/OAuth2/ScopeTest.php | 1 | ||||
| -rw-r--r-- | test/OAuth2/ServerTest.php | 28 | ||||
| -rw-r--r-- | test/OAuth2/Storage/PdoTest.php | 2 | ||||
| -rw-r--r-- | test/OAuth2/Storage/ScopeTest.php | 6 | ||||
| -rw-r--r-- | test/cleanup.php | 15 | ||||
| -rw-r--r-- | test/config/storage.json | 2 | ||||
| -rw-r--r-- | test/lib/OAuth2/Storage/BaseTest.php | 6 | ||||
| -rw-r--r-- | test/lib/OAuth2/Storage/Bootstrap.php | 421 | ||||
| -rw-r--r-- | test/lib/OAuth2/Storage/NullStorage.php | 2 |
18 files changed, 672 insertions, 41 deletions
diff --git a/test/OAuth2/Controller/AuthorizeControllerTest.php b/test/OAuth2/Controller/AuthorizeControllerTest.php index 1bce0ef..c2745d6 100644 --- a/test/OAuth2/Controller/AuthorizeControllerTest.php +++ b/test/OAuth2/Controller/AuthorizeControllerTest.php @@ -203,7 +203,7 @@ class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase $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', + 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true', 'state' => 'xyz', )); @@ -221,7 +221,7 @@ class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase $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&hereisa=querystring', + 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', )); $server->handleAuthorizeRequest($request, $response = new Response(), true); @@ -239,7 +239,7 @@ class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase $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&hereisa=querystring', + 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', 'state' => 'xyz', )); diff --git a/test/OAuth2/Controller/ResourceControllerTest.php b/test/OAuth2/Controller/ResourceControllerTest.php index fb25550..ee6d96f 100644 --- a/test/OAuth2/Controller/ResourceControllerTest.php +++ b/test/OAuth2/Controller/ResourceControllerTest.php @@ -100,7 +100,7 @@ class ResourceControllerTest extends \PHPUnit_Framework_TestCase $this->assertFalse($allow); $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_token'); + $this->assertEquals($response->getParameter('error'), 'expired_token'); $this->assertEquals($response->getParameter('error_description'), 'The access token provided has expired'); } @@ -132,7 +132,7 @@ class ResourceControllerTest extends \PHPUnit_Framework_TestCase $this->assertFalse($allow); $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_token'); + $this->assertEquals($response->getParameter('error'), 'malformed_token'); $this->assertEquals($response->getParameter('error_description'), 'Malformed token (missing "expires")'); } diff --git a/test/OAuth2/Controller/TokenControllerTest.php b/test/OAuth2/Controller/TokenControllerTest.php index f41a95c..d53181d 100644 --- a/test/OAuth2/Controller/TokenControllerTest.php +++ b/test/OAuth2/Controller/TokenControllerTest.php @@ -11,7 +11,7 @@ use OAuth2\Scope; use OAuth2\Request\TestRequest; use OAuth2\Response; -class Controller_TokenControllerTest extends \PHPUnit_Framework_TestCase +class TokenControllerTest extends \PHPUnit_Framework_TestCase { public function testNoGrantType() { diff --git a/test/OAuth2/GrantType/UserCredentialsTest.php b/test/OAuth2/GrantType/UserCredentialsTest.php index 447caf5..18943d0 100644 --- a/test/OAuth2/GrantType/UserCredentialsTest.php +++ b/test/OAuth2/GrantType/UserCredentialsTest.php @@ -138,7 +138,6 @@ class UserCredentialsTest extends \PHPUnit_Framework_TestCase 'password' => 'testpass', // valid password )); - $token = $server->grantAccessToken($request, $response = new Response()); $this->assertNotNull($token); diff --git a/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php b/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php new file mode 100644 index 0000000..4b217c5 --- /dev/null +++ b/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php @@ -0,0 +1,156 @@ +<?php + +namespace OAuth2\OpenID\Controller; + +use OAuth2\OpenID\Controller\AuthorizeController; +use OAuth2\OpenID\ResponseType\IdToken; +use OAuth2\OpenID\ResponseType\TokenIdToken; +use OAuth2\ResponseType\AccessToken; +use OAuth2\Storage\Bootstrap; +use OAuth2\Server; +use OAuth2\Request; +use OAuth2\Response; + +class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase +{ + public function testValidateAuthorizeRequest() + { + $server = $this->getTestServer(); + + $response = new Response(); + $request = new Request(array( + 'client_id' => 'Test Client ID', // valid client id + 'redirect_uri' => 'http://adobe.com', // valid redirect URI + 'response_type' => 'id_token', + 'state' => 'af0ifjsldkj', + 'nonce' => 'n-0S6_WzA2Mj', + )); + + // Test valid id_token request + $server->handleAuthorizeRequest($request, $response, true); + + $parts = parse_url($response->getHttpHeader('Location')); + parse_str($parts['fragment'], $query); + + $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); + $this->assertEquals($query['state'], 'af0ifjsldkj'); + + $this->assertArrayHasKey('id_token', $query); + $this->assertArrayHasKey('state', $query); + $this->assertArrayNotHasKey('access_token', $query); + $this->assertArrayNotHasKey('expires_in', $query); + $this->assertArrayNotHasKey('token_type', $query); + + // Test valid token id_token request + $request->query['response_type'] = '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' response type + $request->query['response_type'] = 'token id_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' => 'anzev', + 'allow_implicit' => true + ); + + $storage = Bootstrap::getInstance()->getMemoryStorage(); + $server = new Server($storage, $config); + + return $server; + } +} diff --git a/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php b/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php index 939b715..90fdd0b 100644 --- a/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php +++ b/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php @@ -2,14 +2,25 @@ namespace OAuth2\OpenID\Controller; +use OAuth2\OpenID\Controller\UserInfoController; use OAuth2\Storage\Bootstrap; use OAuth2\Server; -use OAuth2\GrantType\AuthorizationCode; use OAuth2\Request; use OAuth2\Response; class UserInfoControllerTest extends \PHPUnit_Framework_TestCase { + public function testCreateController() + { + $tokenType = new \OAuth2\TokenType\Bearer(); + $storage = new \OAuth2\Storage\Memory(); + $controller = new UserInfoController($tokenType, $storage, $storage); + + $response = new Response(); + $controller->handleUserInfoRequest(new Request(), $response); + $this->assertEquals(401, $response->getStatusCode()); + } + public function testValidToken() { $server = $this->getTestServer(); @@ -28,6 +39,7 @@ class UserInfoControllerTest extends \PHPUnit_Framework_TestCase { $storage = Bootstrap::getInstance()->getMemoryStorage(); $server = new Server($storage, $config); + return $server; } } diff --git a/test/OAuth2/OpenID/ResponseType/TokenIdTokenTest.php b/test/OAuth2/OpenID/ResponseType/TokenIdTokenTest.php index 488eb08..f687cff 100644 --- a/test/OAuth2/OpenID/ResponseType/TokenIdTokenTest.php +++ b/test/OAuth2/OpenID/ResponseType/TokenIdTokenTest.php @@ -50,7 +50,7 @@ class TokenIdTokenTest extends \PHPUnit_Framework_TestCase // Each part is a base64url encoded json string. $part = str_replace(array('-', '_'), array('+', '/'), $part); $part = base64_decode($part); - $part = json_decode($part, TRUE); + $part = json_decode($part, true); } list($header, $claims, $signature) = $parts; diff --git a/test/OAuth2/ResponseTest.php b/test/OAuth2/ResponseTest.php index c36156f..b814900 100644 --- a/test/OAuth2/ResponseTest.php +++ b/test/OAuth2/ResponseTest.php @@ -12,6 +12,6 @@ class ResponseTest extends \PHPUnit_Framework_TestCase )); $string = $response->getResponseBody('xml'); - $this->assertContains('<response><bar>foo</bar><oates>halland</oates></response>', $string); + $this->assertContains('<response><foo>bar</foo><halland>oates</halland></response>', $string); } } diff --git a/test/OAuth2/ResponseType/CryptoTokenTest.php b/test/OAuth2/ResponseType/CryptoTokenTest.php index 560890b..d1ab89e 100644 --- a/test/OAuth2/ResponseType/CryptoTokenTest.php +++ b/test/OAuth2/ResponseType/CryptoTokenTest.php @@ -8,6 +8,8 @@ use OAuth2\Request\TestRequest; use OAuth2\Storage\Bootstrap; use OAuth2\Storage\CryptoToken as CryptoTokenStorage; use OAuth2\GrantType\ClientCredentials; +use OAuth2\GrantType\UserCredentials; +use OAuth2\GrantType\RefreshToken; class CryptoTokenTest extends \PHPUnit_Framework_TestCase { @@ -69,6 +71,47 @@ class CryptoTokenTest extends \PHPUnit_Framework_TestCase $this->assertTrue($resourceServer->verifyResourceRequest($request)); } + public function testCryptoTokenWithRefreshToken() + { + $server = $this->getTestServer(); + + // add "UserCredentials" grant type and "CryptoToken" response type + // and ensure "CryptoToken" response type has "RefreshToken" storage + $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); + $server->addGrantType(new UserCredentials($memoryStorage)); + $server->addGrantType(new RefreshToken($memoryStorage)); + $server->addResponseType(new CryptoToken($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($cryptoToken = $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('.', $cryptoToken); + $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(); diff --git a/test/OAuth2/ScopeTest.php b/test/OAuth2/ScopeTest.php index 00ec7b6..99f9cf6 100644 --- a/test/OAuth2/ScopeTest.php +++ b/test/OAuth2/ScopeTest.php @@ -3,7 +3,6 @@ namespace OAuth2; use OAuth2\Storage\Memory; -use OAuth2\Storage\Bootstrap; class ScopeTest extends \PHPUnit_Framework_TestCase { diff --git a/test/OAuth2/ServerTest.php b/test/OAuth2/ServerTest.php index d3c8069..fd824fc 100644 --- a/test/OAuth2/ServerTest.php +++ b/test/OAuth2/ServerTest.php @@ -389,6 +389,34 @@ class ServerTest extends \PHPUnit_Framework_TestCase } /** + * 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() diff --git a/test/OAuth2/Storage/PdoTest.php b/test/OAuth2/Storage/PdoTest.php index f6c0549..57eb390 100644 --- a/test/OAuth2/Storage/PdoTest.php +++ b/test/OAuth2/Storage/PdoTest.php @@ -2,8 +2,6 @@ namespace OAuth2\Storage; -use OAuth2\Encryption\Jwt; - class PdoTest extends BaseTest { public function testCreatePdoStorageUsingPdoClass() diff --git a/test/OAuth2/Storage/ScopeTest.php b/test/OAuth2/Storage/ScopeTest.php index 2f7a588..fd1edeb 100644 --- a/test/OAuth2/Storage/ScopeTest.php +++ b/test/OAuth2/Storage/ScopeTest.php @@ -44,6 +44,10 @@ class ScopeTest extends BaseTest // test getting default scope $scopeUtil = new Scope($storage); - $this->assertEquals($scopeUtil->getDefaultScope(), 'defaultscope1 defaultscope2'); + $expected = explode(' ', $scopeUtil->getDefaultScope()); + $actual = explode(' ', 'defaultscope1 defaultscope2'); + sort($expected); + sort($actual); + $this->assertEquals($expected, $actual); } } diff --git a/test/cleanup.php b/test/cleanup.php new file mode 100644 index 0000000..4042eb2 --- /dev/null +++ b/test/cleanup.php @@ -0,0 +1,15 @@ +<?php + +require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); +OAuth2\Autoloader::register(); + +// register test classes +OAuth2\Autoloader::register(dirname(__FILE__).'/lib'); + +// register vendors if possible +if (file_exists(__DIR__.'/../vendor/autoload.php')) { + require_once(__DIR__.'/../vendor/autoload.php'); +} + +// remove the dynamoDB database that was created for this build +OAuth2\Storage\Bootstrap::getInstance()->cleanupTravisDynamoDb();
\ No newline at end of file diff --git a/test/config/storage.json b/test/config/storage.json index 82a7924..2d43c07 100644 --- a/test/config/storage.json +++ b/test/config/storage.json @@ -48,7 +48,7 @@ }, "Test Client ID with Redirect Uri Parts": { "client_secret": "TestSecret4", - "redirect_uri": "http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth" + "redirect_uri": "http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true" }, "Test Some Other Client": { "client_secret": "TestSecret3" diff --git a/test/lib/OAuth2/Storage/BaseTest.php b/test/lib/OAuth2/Storage/BaseTest.php index f7de3c7..579997c 100644 --- a/test/lib/OAuth2/Storage/BaseTest.php +++ b/test/lib/OAuth2/Storage/BaseTest.php @@ -6,13 +6,14 @@ abstract class BaseTest extends \PHPUnit_Framework_TestCase { public function provideStorage() { + $memory = Bootstrap::getInstance()->getMemoryStorage(); + $sqlite = Bootstrap::getInstance()->getSqlitePdo(); $mysql = Bootstrap::getInstance()->getMysqlPdo(); $postgres = Bootstrap::getInstance()->getPostgresPdo(); - $sqlite = Bootstrap::getInstance()->getSqlitePdo(); $mongo = Bootstrap::getInstance()->getMongo(); $redis = Bootstrap::getInstance()->getRedisStorage(); $cassandra = Bootstrap::getInstance()->getCassandraStorage(); - $memory = Bootstrap::getInstance()->getMemoryStorage(); + $dynamodb = Bootstrap::getInstance()->getDynamoDbStorage(); /* hack until we can fix "default_scope" dependencies in other tests */ $memory->defaultScope = 'defaultscope1 defaultscope2'; @@ -25,6 +26,7 @@ abstract class BaseTest extends \PHPUnit_Framework_TestCase array($mongo), array($redis), array($cassandra), + array($dynamodb), ); } } diff --git a/test/lib/OAuth2/Storage/Bootstrap.php b/test/lib/OAuth2/Storage/Bootstrap.php index 8d7fe0d..129ca2f 100644 --- a/test/lib/OAuth2/Storage/Bootstrap.php +++ b/test/lib/OAuth2/Storage/Bootstrap.php @@ -4,6 +4,8 @@ namespace OAuth2\Storage; class Bootstrap { + const DYNAMODB_PHP_VERSION = '5.5'; + protected static $instance; private $mysql; private $sqlite; @@ -12,6 +14,7 @@ class Bootstrap private $redis; private $cassandra; private $configDir; + private $dynamodb; public function __construct() { @@ -51,8 +54,6 @@ class Bootstrap $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $this->populatePostgresDb($pdo); $this->postgres = new Pdo($pdo); - } else { - $this->postgres = new NullStorage('Postgres', 'Unable to connect to postgres on localhost with user "postgres"'); } } else { $this->postgres = new NullStorage('Postgres', 'Missing postgres PDO extension.'); @@ -69,7 +70,7 @@ class Bootstrap return $pdo; } catch (\PDOException $e) { - exit($e->getMessage()); + $this->postgres = new NullStorage('Postgres', $e->getMessage()); } } @@ -113,12 +114,20 @@ class Bootstrap public function getMysqlPdo() { if (!$this->mysql) { - $pdo = new \PDO('mysql:host=localhost;', 'root'); - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $this->removeMysqlDb($pdo); - $this->createMysqlDb($pdo); + $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'); + } - $this->mysql = new Pdo($pdo); + if ($pdo) { + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $this->removeMysqlDb($pdo); + $this->createMysqlDb($pdo); + + $this->mysql = new Pdo($pdo); + } } return $this->mysql; @@ -127,7 +136,7 @@ class Bootstrap public function getMongo() { if (!$this->mongo) { - $skipMongo = isset($_SERVER['SKIP_MONGO_TESTS']) && $_SERVER['SKIP_MONGO_TESTS']; + $skipMongo = $this->getEnvVar('SKIP_MONGO_TESTS'); if (!$skipMongo && class_exists('MongoClient')) { $mongo = new \MongoClient('mongodb://localhost:27017', array('connect' => false)); if ($this->testMongoConnection($mongo)) { @@ -277,14 +286,10 @@ class Bootstrap public function runPdoSql(\PDO $pdo) { - $pdo->exec('CREATE TABLE oauth_clients (client_id TEXT, client_secret TEXT, redirect_uri TEXT, grant_types TEXT, scope TEXT, user_id TEXT, public_key TEXT)'); - $pdo->exec('CREATE TABLE oauth_access_tokens (access_token TEXT, client_id TEXT, user_id TEXT, expires TIMESTAMP, scope TEXT)'); - $pdo->exec('CREATE TABLE oauth_authorization_codes (authorization_code TEXT, client_id TEXT, user_id TEXT, redirect_uri TEXT, expires TIMESTAMP, scope TEXT, id_token TEXT)'); - $pdo->exec('CREATE TABLE oauth_users (username TEXT, password TEXT, first_name TEXT, last_name TEXT, scope TEXT, email TEXT, email_verified BOOLEAN)'); - $pdo->exec('CREATE TABLE oauth_refresh_tokens (refresh_token TEXT, client_id TEXT, user_id TEXT, expires TIMESTAMP, scope TEXT)'); - $pdo->exec('CREATE TABLE oauth_scopes (scope TEXT, is_default BOOLEAN)'); - $pdo->exec('CREATE TABLE oauth_public_keys (client_id TEXT, public_key TEXT, private_key TEXT, encryption_algorithm VARCHAR(100) DEFAULT \'RS256\')'); - $pdo->exec('CREATE TABLE oauth_jwt (client_id VARCHAR(80), subject VARCHAR(80), public_key VARCHAR(2000))'); + $storage = new Pdo($pdo); + foreach (explode(';', $storage->getBuildSql()) as $statement) { + $result = $pdo->exec($statement); + } // set up scopes $sql = 'INSERT INTO oauth_scopes (scope) VALUES (?)'; @@ -305,12 +310,12 @@ class Bootstrap $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, user_id) VALUES (?, ?, ?)'; - $pdo->prepare($sql)->execute(array('testtoken', 'Some Client', null)); - $pdo->prepare($sql)->execute(array('accesstoken-openid-connect', 'Some Client', 'testuser')); + $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) VALUES (?, ?)'; - $pdo->prepare($sql)->execute(array('testcode', 'Some Client')); + $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)); @@ -326,7 +331,6 @@ class Bootstrap $pdo->prepare($sql)->execute(array('oauth_test_client', 'test_subject', $this->getTestPublicKey())); } - public function getSqliteDir() { return $this->configDir. '/test.sqlite'; @@ -407,4 +411,375 @@ class Bootstrap { 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/test/lib/OAuth2/Storage/NullStorage.php b/test/lib/OAuth2/Storage/NullStorage.php index 46a200c..6caa620 100644 --- a/test/lib/OAuth2/Storage/NullStorage.php +++ b/test/lib/OAuth2/Storage/NullStorage.php @@ -29,4 +29,4 @@ class NullStorage extends Memory return $this->name; } -}
\ No newline at end of file +} |
