diff --git a/.docker/Dockerfile b/.docker/Dockerfile
new file mode 100644
index 000000000..4c8a13028
--- /dev/null
+++ b/.docker/Dockerfile
@@ -0,0 +1,34 @@
+ARG PHP_VERSION=8.3
+FROM php:${PHP_VERSION}-cli-alpine
+
+RUN apk add --no-cache --virtual .build-deps \
+ $PHPIZE_DEPS \
+ cmake \
+ linux-headers \
+ openssl-dev \
+ zlib-dev \
+ libpq-dev \
+ && apk add --no-cache \
+ git \
+ unzip \
+ libpq \
+ libstdc++ \
+ && docker-php-ext-install -j$(nproc) \
+ pdo_mysql \
+ pdo_pgsql \
+ && pecl install mongodb redis couchbase \
+ && docker-php-ext-enable mongodb redis couchbase \
+ && runDeps="$( \
+ scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
+ | tr ',' '\n' | sort -u \
+ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
+ )" \
+ && apk add --no-cache $runDeps \
+ && apk del .build-deps \
+ && rm -rf /tmp/* /var/cache/apk/* \
+ && php -m | grep -q couchbase \
+ && php -m | grep -q mongodb
+
+COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
+
+WORKDIR /app
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
new file mode 100644
index 000000000..c3c1202c8
--- /dev/null
+++ b/.github/workflows/docker.yml
@@ -0,0 +1,50 @@
+name: Build CI Images
+on:
+ workflow_dispatch:
+ schedule:
+ # Weekly rebuild to pick up PHP patch updates
+ - cron: '0 6 * * 1'
+ push:
+ branches:
+ - main
+ - php85
+ paths:
+ - '.docker/Dockerfile'
+ - '.github/workflows/docker.yml'
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: ${{ github.repository_owner }}/oauth2-php-ci
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ strategy:
+ matrix:
+ php: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]
+ name: "Build PHP ${{ matrix.php }}"
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Log in to GHCR
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Build and push
+ uses: docker/build-push-action@v6
+ with:
+ context: .docker
+ build-args: PHP_VERSION=${{ matrix.php }}
+ push: true
+ tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ matrix.php }}
+ cache-from: type=gha,scope=php-${{ matrix.php }}
+ cache-to: type=gha,mode=max,scope=php-${{ matrix.php }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fe13e48b8..a7bfadddd 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,68 +7,82 @@ on:
jobs:
test:
runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/maksimovic/oauth2-php-ci:${{ matrix.php }}
services:
redis:
image: redis
- ports:
- - 6379:6379
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mongodb:
image: mongo
- ports:
- - 27017:27017
- myriadb:
+ options: --health-cmd="mongosh --eval 'db.runCommand(\"ping\").ok'" --health-interval=10s --health-timeout=5s --health-retries=5
+ mariadb:
image: mariadb
env:
MYSQL_ROOT_PASSWORD: root
- ports:
- - 3808:3808
- - 3306:3306
+ options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=5
postgres:
image: postgres
env:
POSTGRES_DB: oauth2_server_php
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
- ports:
- - 5432:5432
options: --health-cmd="pg_isready -h localhost" --health-interval=10s --health-timeout=5s --health-retries=5
+ cassandra:
+ image: cassandra:4
+ options: --health-cmd="cqlsh -e 'describe cluster'" --health-interval=15s --health-timeout=10s --health-retries=10
+ dynamodb:
+ image: amazon/dynamodb-local
+ couchbase:
+ image: couchbase/server:community-7.6.2
strategy:
matrix:
- php: [ 7.2, 7.3, 7.4, "8.0", 8.1, 8.2 ]
+ php: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]
name: "PHP ${{ matrix.php }} Unit Test"
+ env:
+ MYSQL_HOST: mariadb
+ POSTGRES_HOST: postgres
+ REDIS_HOST: redis
+ MONGODB_HOST: mongodb
+ CASSANDRA_HOST: cassandra
+ DYNAMODB_ENDPOINT: http://dynamodb:8000
+ CB_CONNECTION_STRING: couchbase://couchbase
+ CB_USERNAME: Administrator
+ CB_PASSWORD: password
+ CB_BUCKET: oauth2test
steps:
- - uses: actions/checkout@v2
- - uses: codecov/codecov-action@v1
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php }}
- extensions: mongodb, mbstring, intl, redis, pdo_mysql
+ - uses: actions/checkout@v5
- name: Install composer dependencies
- uses: nick-invision/retry@v1
- with:
- timeout_minutes: 10
- max_attempts: 3
- command: composer install
+ run: |
+ composer install --no-interaction
+ composer require mongodb/mongodb:'^1.20 || ^2.0' couchbase/couchbase:^4.4 --no-interaction
+ - name: Setup Couchbase
+ run: |
+ echo "Waiting for Couchbase..."
+ timeout 90 sh -c 'until wget -qO- http://couchbase:8091/ui/index.html > /dev/null 2>&1; do sleep 2; done'
+ echo "Couchbase responding"
+
+ wget -qO- --post-data 'clusterName=ci&services=kv&memoryQuota=256&afamily=ipv4&afamilyOnly=false&nodeEncryption=off&username=Administrator&password=password&port=SAME&sendStats=false' \
+ http://couchbase:8091/clusterInit
+ echo "Couchbase cluster initialized"
+
+ wget -qO- --post-data 'name=oauth2test&ramQuota=128&bucketType=couchbase' \
+ --header="Authorization: Basic $(echo -n Administrator:password | base64)" \
+ http://couchbase:8091/pools/default/buckets
+ echo "Couchbase bucket created"
+
+ timeout 30 sh -c 'until wget -qO- --header="Authorization: Basic $(echo -n Administrator:password | base64)" http://couchbase:8091/pools/default/buckets/oauth2test 2>/dev/null | grep -q "\"status\":\"healthy\""; do sleep 2; done'
+ echo "Couchbase ready"
- name: Run PHPUnit
- run: vendor/bin/phpunit -v
+ run: composer test
+
phpstan:
- name: "PHPStan"
runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/maksimovic/oauth2-php-ci:8.3
steps:
- - uses: actions/checkout@v2
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: 8.1
+ - uses: actions/checkout@v5
- name: Install composer dependencies
- uses: nick-invision/retry@v1
- with:
- timeout_minutes: 10
- max_attempts: 3
- command: composer install
+ run: composer install --no-interaction
- name: Run PHPStan
- run: |
- composer require phpstan/phpstan
- vendor/bin/phpstan analyse --level=0 src/
+ run: composer analyze
diff --git a/composer.json b/composer.json
index 50a950774..66cc9cbd2 100644
--- a/composer.json
+++ b/composer.json
@@ -16,21 +16,27 @@
"psr-0": { "OAuth2": "src/" }
},
"require":{
- "php":">=7.2"
+ "php":"^8.1"
},
"require-dev": {
- "phpunit/phpunit": "^7.5||^8.0",
- "aws/aws-sdk-php": "^2.8",
- "firebase/php-jwt": "^6.4",
- "predis/predis": "^1.1",
- "thobbs/phpcassa": "dev-master",
- "yoast/phpunit-polyfills": "^1.0"
+ "phpunit/phpunit": "^10.5",
+ "aws/aws-sdk-php": "^3.0",
+ "firebase/php-jwt": "^7.0",
+ "predis/predis": "^2.0",
+ "mroosz/php-cassandra": "^1.2",
+ "phpstan/phpstan": "^2.1"
+ },
+ "scripts": {
+ "test": "phpunit",
+ "test:coverage": "phpunit --coverage-text",
+ "analyze": "phpstan analyse --memory-limit=512M"
},
"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": "~v6.4 is required to use JWT features",
- "mongodb/mongodb": "^1.1 is required to use MongoDB storage"
+ "mroosz/php-cassandra": "^1.2 is required to use Cassandra storage",
+ "aws/aws-sdk-php": "^3.0 is required to use DynamoDB storage",
+ "firebase/php-jwt": "^7.0 is required to use JWT features",
+ "mongodb/mongodb": "^1.20 || ^2.0 is required to use MongoDB storage",
+ "couchbase/couchbase": "^4.4 is required to use Couchbase storage (requires ext-couchbase)"
}
}
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 000000000..d0a164b61
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,6 @@
+parameters:
+ level: 0
+ paths:
+ - src/
+ scanFiles:
+ - stubs/couchbase.stub
diff --git a/phpunit.xml b/phpunit.xml
index 6e663e39d..66b040c02 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,14 +1,14 @@
@@ -16,9 +16,9 @@
-
-
+
+
./src/OAuth2/
-
-
+
+
diff --git a/src/OAuth2/Controller/AuthorizeController.php b/src/OAuth2/Controller/AuthorizeController.php
index 181f884a6..93e5b782f 100644
--- a/src/OAuth2/Controller/AuthorizeController.php
+++ b/src/OAuth2/Controller/AuthorizeController.php
@@ -257,7 +257,7 @@ public function validateAuthorizeRequest(RequestInterface $request, ResponseInte
$response_type = $request->query('response_type', $request->request('response_type'));
// for multiple-valued response types - make them alphabetical
- if (false !== strpos($response_type, ' ')) {
+ if (false !== strpos((string) $response_type, ' ')) {
$types = explode(' ', $response_type);
sort($types);
$response_type = ltrim(implode(' ', $types));
diff --git a/src/OAuth2/Controller/TokenController.php b/src/OAuth2/Controller/TokenController.php
index 1e21b5f67..01c8798ba 100644
--- a/src/OAuth2/Controller/TokenController.php
+++ b/src/OAuth2/Controller/TokenController.php
@@ -118,13 +118,13 @@ public function handleTokenRequest(RequestInterface $request, ResponseInterface
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
{
- if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
+ if (strtolower((string) $request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
- if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
+ if (strtolower((string) $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, OPTIONS'));
@@ -263,7 +263,7 @@ public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
$identifier = $grantType->getQueryStringIdentifier();
}
- $this->grantTypes[$identifier] = $grantType;
+ $this->grantTypes[(string) $identifier] = $grantType;
}
/**
@@ -293,13 +293,13 @@ public function handleRevokeRequest(RequestInterface $request, ResponseInterface
*/
public function revokeToken(RequestInterface $request, ResponseInterface $response)
{
- if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
+ if (strtolower((string) $request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
- if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
+ if (strtolower((string) $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, OPTIONS'));
diff --git a/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
index ee113a0e5..01e14540b 100644
--- a/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
+++ b/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
@@ -25,7 +25,7 @@ public function createAccessToken(AccessTokenInterface $accessToken, $client_id,
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));
+ $scopes = explode(' ', trim((string) $scope));
$includeRefreshToken = in_array('offline_access', $scopes);
}
diff --git a/src/OAuth2/Scope.php b/src/OAuth2/Scope.php
index 3ba6e5328..b38b757a9 100644
--- a/src/OAuth2/Scope.php
+++ b/src/OAuth2/Scope.php
@@ -47,8 +47,8 @@ public function __construct($storage = null)
*/
public function checkScope($required_scope, $available_scope)
{
- $required_scope = explode(' ', trim($required_scope));
- $available_scope = explode(' ', trim($available_scope));
+ $required_scope = explode(' ', trim((string) $required_scope));
+ $available_scope = explode(' ', trim((string) $available_scope));
return (count(array_diff($required_scope, $available_scope)) == 0);
}
diff --git a/src/OAuth2/Server.php b/src/OAuth2/Server.php
index e5716358d..6b4881ab2 100644
--- a/src/OAuth2/Server.php
+++ b/src/OAuth2/Server.php
@@ -453,7 +453,7 @@ public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
$identifier = $grantType->getQueryStringIdentifier();
}
- $this->grantTypes[$identifier] = $grantType;
+ $this->grantTypes[(string) $identifier] = $grantType;
// persist added grant type down to TokenController
if (!is_null($this->tokenController)) {
@@ -473,7 +473,7 @@ public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
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($key) && 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]));
}
@@ -516,7 +516,7 @@ public function addResponseType(ResponseTypeInterface $responseType, $key = null
{
$key = $this->normalizeResponseType($key);
- if (isset($this->responseTypeMap[$key])) {
+ if (!is_null($key) && 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]));
}
diff --git a/src/OAuth2/Storage/Cassandra.php b/src/OAuth2/Storage/Cassandra.php
index 3a138bb52..fa4b136ab 100644
--- a/src/OAuth2/Storage/Cassandra.php
+++ b/src/OAuth2/Storage/Cassandra.php
@@ -2,9 +2,8 @@
namespace OAuth2\Storage;
-use phpcassa\ColumnFamily;
-use phpcassa\ColumnSlice;
-use phpcassa\Connection\ConnectionPool;
+use Cassandra\Connection;
+use Cassandra\Connection\StreamNodeConfig;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use InvalidArgumentException;
@@ -12,14 +11,17 @@
/**
* Cassandra storage for all storage types
*
- * To use, install "thobbs/phpcassa" via composer:
+ * To use, install "mroosz/php-cassandra" via composer:
*
- * composer require thobbs/phpcassa:dev-master
+ * composer require mroosz/php-cassandra
*
*
* Once this is done, instantiate the connection:
*
- * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160'));
+ * $cassandra = new \Cassandra\Connection([
+ * new \Cassandra\Connection\StreamNodeConfig(host: '127.0.0.1', port: 9042),
+ * ], keyspace: 'oauth2');
+ * $cassandra->connect();
*
*
* Then, register the storage client:
@@ -27,8 +29,6 @@
* $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,
@@ -41,48 +41,50 @@ class Cassandra implements AuthorizationCodeInterface,
UserClaimsInterface,
OpenIDAuthorizationCodeInterface
{
-
private $cache;
- /**
- * @var ConnectionPool
- */
- protected $cassandra;
+ protected Connection $connection;
- /**
- * @var array
- */
- protected $config;
+ protected array $config;
/**
- * Cassandra Storage! uses phpCassa
- *
- * @param ConnectionPool|array $connection
- * @param array $config
+ * @param Connection|array $connection A Connection instance or a configuration array
+ * @param array $config
*
* @throws InvalidArgumentException
*/
- public function __construct($connection = array(), array $config = array())
+ public function __construct($connection, 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');
- }
+ if ($connection instanceof Connection) {
+ $this->connection = $connection;
+ } elseif (is_array($connection)) {
$connection = array_merge(array(
+ 'host' => '127.0.0.1',
+ 'port' => 9042,
'keyspace' => 'oauth2',
- 'servers' => null,
+ 'username' => null,
+ 'password' => null,
), $connection);
- $this->cassandra = new ConnectionPool($connection['keyspace'], $connection['servers']);
+ $nodeConfig = new StreamNodeConfig(
+ host: $connection['host'],
+ port: $connection['port'],
+ username: $connection['username'],
+ password: $connection['password'],
+ );
+
+ $this->connection = new Connection([$nodeConfig], keyspace: $connection['keyspace']);
+ $this->connection->connect();
+ } else {
+ throw new InvalidArgumentException(
+ 'First argument to OAuth2\Storage\Cassandra must be an instance of Cassandra\Connection or a configuration array'
+ );
}
$this->config = array_merge(array(
- // cassandra config
- 'column_family' => 'auth',
+ 'table' => 'oauth_data',
- // key names
+ // key prefixes
'client_key' => 'oauth_clients:',
'access_token_key' => 'oauth_access_tokens:',
'refresh_token_key' => 'oauth_refresh_tokens:',
@@ -90,107 +92,98 @@ public function __construct($connection = array(), array $config = array())
'user_key' => 'oauth_users:',
'jwt_key' => 'oauth_jwt:',
'scope_key' => 'oauth_scopes:',
- 'public_key_key' => 'oauth_public_keys:',
+ 'public_key_key' => 'oauth_public_keys:',
), $config);
}
- /**
- * @param $key
- * @return bool|mixed
- */
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) {
+ $result = $this->connection->query(
+ sprintf('SELECT value FROM %s WHERE key = ?', $this->config['table']),
+ [$key]
+ )->asRowsResult();
+
+ foreach ($result as $row) {
+ return json_decode($row['value'], true);
+ }
+ } catch (\Exception $e) {
return false;
}
- return json_decode($value, true);
+ return false;
}
- /**
- * @param $key
- * @param $value
- * @param int $expire
- * @return bool
- */
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 {
+
+ try {
+ if ($expire > 0) {
$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;
+ if ($seconds < 1) {
+ $seconds = 1;
+ }
+ $this->connection->query(
+ sprintf('INSERT INTO %s (key, value) VALUES (?, ?) USING TTL %d', $this->config['table'], $seconds),
+ [$key, $str]
+ );
+ } else {
+ $this->connection->query(
+ sprintf('INSERT INTO %s (key, value) VALUES (?, ?)', $this->config['table']),
+ [$key, $str]
+ );
}
+ } catch (\Exception $e) {
+ return false;
}
return true;
}
- /**
- * @param $key
- * @return bool
- */
protected function expireValue($key)
{
unset($this->cache[$key]);
- $cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
+ try {
+ // check if the key exists before deleting
+ $result = $this->connection->query(
+ sprintf('SELECT key FROM %s WHERE key = ?', $this->config['table']),
+ [$key]
+ )->asRowsResult();
+
+ $found = false;
+ foreach ($result as $row) {
+ $found = true;
+ break;
+ }
- if ($cf->get_count($key) > 0) {
- try {
- // __data key set as C* requires a field
- $cf->remove($key, array('__data'));
- } catch (\Exception $e) {
+ if (!$found) {
return false;
}
- return true;
+ $this->connection->query(
+ sprintf('DELETE FROM %s WHERE key = ?', $this->config['table']),
+ [$key]
+ );
+ } catch (\Exception $e) {
+ return false;
}
- return false;
+ return true;
}
- /**
- * @param string $code
- * @return bool|mixed
- */
public function getAuthorizationCode($code)
{
return $this->getValue($this->config['code_key'] . $code);
}
- /**
- * @param string $authorization_code
- * @param mixed $client_id
- * @param mixed $user_id
- * @param string $redirect_uri
- * @param int $expires
- * @param string $scope
- * @param string $id_token
- * @return bool
- */
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
return $this->setValue(
@@ -200,10 +193,6 @@ public function setAuthorizationCode($authorization_code, $client_id, $user_id,
);
}
- /**
- * @param string $code
- * @return bool
- */
public function expireAuthorizationCode($code)
{
$key = $this->config['code_key'] . $code;
@@ -212,11 +201,6 @@ public function expireAuthorizationCode($code)
return $this->expireValue($key);
}
- /**
- * @param string $username
- * @param string $password
- * @return bool
- */
public function checkUserCredentials($username, $password)
{
if ($user = $this->getUser($username)) {
@@ -226,56 +210,32 @@ public function checkUserCredentials($username, $password)
return false;
}
- /**
- * plaintext passwords are bad! Override this for your application
- *
- * @param array $user
- * @param string $password
- * @return bool
- */
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);
}
- /**
- * @param string $username
- * @return array|bool|false
- */
public function getUserDetails($username)
{
return $this->getUser($username);
}
- /**
- * @param string $username
- * @return array|bool
- */
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);
}
- /**
- * @param string $username
- * @param string $password
- * @param string $first_name
- * @param string $last_name
- * @return bool
- */
public function setUser($username, $password, $first_name = null, $last_name = null)
{
$password = $this->hashPassword($password);
@@ -286,11 +246,6 @@ public function setUser($username, $password, $first_name = null, $last_name = n
);
}
- /**
- * @param mixed $client_id
- * @param string $client_secret
- * @return bool
- */
public function checkClientCredentials($client_id, $client_secret = null)
{
if (!$client = $this->getClientDetails($client_id)) {
@@ -301,10 +256,6 @@ public function checkClientCredentials($client_id, $client_secret = null)
&& $client['client_secret'] == $client_secret;
}
- /**
- * @param $client_id
- * @return bool
- */
public function isPublicClient($client_id)
{
if (!$client = $this->getClientDetails($client_id)) {
@@ -314,24 +265,11 @@ public function isPublicClient($client_id)
return empty($client['client_secret']);
}
- /**
- * @param $client_id
- * @return array|bool|mixed
- */
public function getClientDetails($client_id)
{
return $this->getValue($this->config['client_key'] . $client_id);
}
- /**
- * @param $client_id
- * @param null $client_secret
- * @param null $redirect_uri
- * @param null $grant_types
- * @param null $scope
- * @param null $user_id
- * @return bool
- */
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{
return $this->setValue(
@@ -340,11 +278,6 @@ public function setClientDetails($client_id, $client_secret = null, $redirect_ur
);
}
- /**
- * @param $client_id
- * @param $grant_type
- * @return bool
- */
public function checkRestrictedGrantType($client_id, $grant_type)
{
$details = $this->getClientDetails($client_id);
@@ -354,27 +287,14 @@ public function checkRestrictedGrantType($client_id, $grant_type)
return in_array($grant_type, (array) $grant_types);
}
- // if grant_types are not defined, then none are restricted
return true;
}
- /**
- * @param $refresh_token
- * @return bool|mixed
- */
public function getRefreshToken($refresh_token)
{
return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
}
- /**
- * @param $refresh_token
- * @param $client_id
- * @param $user_id
- * @param $expires
- * @param null $scope
- * @return bool
- */
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{
return $this->setValue(
@@ -384,85 +304,50 @@ public function setRefreshToken($refresh_token, $client_id, $user_id, $expires,
);
}
- /**
- * @param $refresh_token
- * @return bool
- */
public function unsetRefreshToken($refresh_token)
{
return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
}
- /**
- * @param string $access_token
- * @return array|bool|mixed|null
- */
public function getAccessToken($access_token)
{
- return $this->getValue($this->config['access_token_key'].$access_token);
+ return $this->getValue($this->config['access_token_key'] . $access_token);
}
- /**
- * @param string $access_token
- * @param mixed $client_id
- * @param mixed $user_id
- * @param int $expires
- * @param null $scope
- * @return bool
- */
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{
return $this->setValue(
- $this->config['access_token_key'].$access_token,
+ $this->config['access_token_key'] . $access_token,
compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
$expires
);
}
- /**
- * @param $access_token
- * @return bool
- */
public function unsetAccessToken($access_token)
{
return $this->expireValue($this->config['access_token_key'] . $access_token);
}
- /**
- * @param $scope
- * @return bool
- */
public function scopeExists($scope)
{
$scope = explode(' ', $scope);
- $result = $this->getValue($this->config['scope_key'].'supported:global');
+ $result = $this->getValue($this->config['scope_key'] . 'supported:global');
$supportedScope = explode(' ', (string) $result);
return (count(array_diff($scope, $supportedScope)) == 0);
}
- /**
- * @param null $client_id
- * @return bool|mixed
- */
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');
+ 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;
}
- /**
- * @param $scope
- * @param null $client_id
- * @param string $type
- * @return bool
- * @throws \InvalidArgumentException
- */
public function setScope($scope, $client_id = null, $type = 'supported')
{
if (!in_array($type, array('default', 'supported'))) {
@@ -470,50 +355,35 @@ public function setScope($scope, $client_id = null, $type = 'supported')
}
if (is_null($client_id)) {
- $key = $this->config['scope_key'].$type.':global';
+ $key = $this->config['scope_key'] . $type . ':global';
} else {
- $key = $this->config['scope_key'].$type.':'.$client_id;
+ $key = $this->config['scope_key'] . $type . ':' . $client_id;
}
return $this->setValue($key, $scope);
}
- /**
- * @param $client_id
- * @param $subject
- * @return bool|null
- */
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 ) {
+ if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
return $jwt['key'];
}
return null;
}
- /**
- * @param $client_id
- * @param $key
- * @param null $subject
- * @return bool
- */
public function setClientKey($client_id, $key, $subject = null)
{
return $this->setValue($this->config['jwt_key'] . $client_id, array(
'key' => $key,
- 'subject' => $subject
+ 'subject' => $subject,
));
}
- /**
- * @param $client_id
- * @return bool|null
- */
public function getClientScope($client_id)
{
if (!$clientDetails = $this->getClientDetails($client_id)) {
@@ -527,38 +397,16 @@ public function getClientScope($client_id)
return null;
}
- /**
- * @param $client_id
- * @param $subject
- * @param $audience
- * @param $expiration
- * @param $jti
- * @throws \Exception
- */
public function getJti($client_id, $subject, $audience, $expiration, $jti)
{
- //TODO: Needs cassandra implementation.
throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.');
}
- /**
- * @param $client_id
- * @param $subject
- * @param $audience
- * @param $expiration
- * @param $jti
- * @throws \Exception
- */
public function setJti($client_id, $subject, $audience, $expiration, $jti)
{
- //TODO: Needs cassandra implementation.
throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
}
- /**
- * @param string $client_id
- * @return mixed
- */
public function getPublicKey($client_id = '')
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@@ -571,10 +419,6 @@ public function getPublicKey($client_id = '')
}
}
- /**
- * @param string $client_id
- * @return mixed
- */
public function getPrivateKey($client_id = '')
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@@ -587,10 +431,6 @@ public function getPrivateKey($client_id = '')
}
}
- /**
- * @param null $client_id
- * @return mixed|string
- */
public function getEncryptionAlgorithm($client_id = null)
{
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@@ -605,11 +445,6 @@ public function getEncryptionAlgorithm($client_id = null)
return 'RS256';
}
- /**
- * @param mixed $user_id
- * @param string $claims
- * @return array|bool
- */
public function getUserClaims($user_id, $claims)
{
$userDetails = $this->getUserDetails($user_id);
@@ -620,12 +455,10 @@ public function getUserClaims($user_id, $claims)
$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));
@@ -636,11 +469,6 @@ public function getUserClaims($user_id, $claims)
return $userClaims;
}
- /**
- * @param $claim
- * @param $userDetails
- * @return array
- */
protected function getUserClaim($claim, $userDetails)
{
$userClaims = array();
@@ -649,7 +477,7 @@ protected function getUserClaim($claim, $userDetails)
foreach ($claimValues as $value) {
if ($value == 'email_verified') {
- $userClaims[$value] = $userDetails[$value]=='true' ? true : false;
+ $userClaims[$value] = $userDetails[$value] == 'true' ? true : false;
} else {
$userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
}
@@ -657,4 +485,4 @@ protected function getUserClaim($claim, $userDetails)
return $userClaims;
}
-}
\ No newline at end of file
+}
diff --git a/src/OAuth2/Storage/CouchbaseDB.php b/src/OAuth2/Storage/CouchbaseDB.php
index 31b0cd301..c59a104ac 100755
--- a/src/OAuth2/Storage/CouchbaseDB.php
+++ b/src/OAuth2/Storage/CouchbaseDB.php
@@ -2,12 +2,17 @@
namespace OAuth2\Storage;
-use Couchbase;
+use Couchbase\Cluster;
+use Couchbase\ClusterOptions;
+use Couchbase\Collection;
+use Couchbase\Exception\DocumentNotFoundException;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
/**
* Simple Couchbase storage for all storage types
*
+ * Uses Couchbase SDK 4.x (ext-couchbase ^4.0).
+ *
* This class should be extended or overridden as required
*
* NOTE: Passwords are stored in plaintext, which is never
@@ -23,59 +28,80 @@ class CouchbaseDB implements AuthorizationCodeInterface,
JwtBearerInterface,
OpenIDAuthorizationCodeInterface
{
- protected $db;
- protected $config;
-
- public function __construct($connection, $config = array())
+ protected Collection $collection;
+ protected array $config;
+
+ /**
+ * @param Collection|array $connection A Couchbase\Collection instance or a config array
+ * with keys: connection_string, username, password, bucket, scope (optional), collection (optional)
+ * @param array $config Table name overrides
+ */
+ public function __construct($connection, array $config = [])
{
- if (!class_exists(Couchbase::class)) {
- throw new \RuntimeException('Missing Couchbase');
- }
-
- if ($connection instanceof Couchbase) {
- $this->db = $connection;
+ if ($connection instanceof Collection) {
+ $this->collection = $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');
+ if (!is_array($connection)) {
+ throw new \InvalidArgumentException(
+ 'First argument to OAuth2\Storage\CouchbaseDB must be a Couchbase\Collection or a configuration array'
+ );
}
- $this->db = new Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
+ $options = new ClusterOptions();
+ $options->credentials($connection['username'] ?? '', $connection['password'] ?? '');
+ $cluster = new Cluster($connection['connection_string'], $options);
+ $bucket = $cluster->bucket($connection['bucket']);
+ $scope = $bucket->scope($connection['scope'] ?? '_default');
+ $this->collection = $scope->collection($connection['collection'] ?? '_default');
}
- $this->config = array_merge(array(
+ $this->config = array_merge([
'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);
+ ], $config);
}
- // Helper function to access couchbase item by type:
- protected function getObjectByType($name,$id)
+ /**
+ * Build a document key from a table name config key and an id.
+ */
+ protected function buildKey(string $name, string $id): string
{
- return json_decode($this->db->get($this->config[$name].'-'.$id),true);
+ return $this->config[$name] . '-' . $id;
}
- // Helper function to set couchbase item by type:
- protected function setObjectByType($name,$id,$array)
+ protected function getObjectByType(string $name, string $id): ?array
{
- $array['type'] = $name;
+ try {
+ $result = $this->collection->get($this->buildKey($name, $id));
+ return $result->content();
+ } catch (DocumentNotFoundException) {
+ return null;
+ }
+ }
- return $this->db->set($this->config[$name].'-'.$id,json_encode($array));
+ protected function setObjectByType(string $name, string $id, array $data): void
+ {
+ $data['type'] = $name;
+ $this->collection->upsert($this->buildKey($name, $id), $data);
}
- // Helper function to delete couchbase item by type, wait for persist to at least 1 node
- protected function deleteObjectByType($name,$id)
+ protected function deleteObjectByType(string $name, string $id): void
{
- $this->db->delete($this->config[$name].'-'.$id,"",1);
+ try {
+ $this->collection->remove($this->buildKey($name, $id));
+ } catch (DocumentNotFoundException) {
+ // already gone
+ }
}
/* ClientCredentialsInterface */
public function checkClientCredentials($client_id, $client_secret = null)
{
- if ($result = $this->getObjectByType('client_table',$client_id)) {
+ if ($result = $this->getObjectByType('client_table', $client_id)) {
return $result['client_secret'] == $client_secret;
}
@@ -84,7 +110,7 @@ public function checkClientCredentials($client_id, $client_secret = null)
public function isPublicClient($client_id)
{
- if (!$result = $this->getObjectByType('client_table',$client_id)) {
+ if (!$result = $this->getObjectByType('client_table', $client_id)) {
return false;
}
@@ -94,33 +120,21 @@ public function isPublicClient($client_id)
/* ClientInterface */
public function getClientDetails($client_id)
{
- $result = $this->getObjectByType('client_table',$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,
- ));
- }
+ $this->setObjectByType('client_table', $client_id, [
+ 'client_id' => $client_id,
+ 'client_secret' => $client_secret,
+ 'redirect_uri' => $redirect_uri,
+ 'grant_types' => $grant_types,
+ 'scope' => $scope,
+ 'user_id' => $user_id,
+ ]);
return true;
}
@@ -141,78 +155,63 @@ public function checkRestrictedGrantType($client_id, $grant_type)
/* AccessTokenInterface */
public function getAccessToken($access_token)
{
- $token = $this->getObjectByType('access_token_table',$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
- ));
- }
+ $this->setObjectByType('access_token_table', $access_token, [
+ 'access_token' => $access_token,
+ 'client_id' => $client_id,
+ 'expires' => $expires,
+ 'user_id' => $user_id,
+ 'scope' => $scope,
+ ]);
return true;
}
+ public function unsetAccessToken($access_token)
+ {
+ try {
+ $this->collection->remove($this->buildKey('access_token_table', $access_token));
+
+ return true;
+ } catch (DocumentNotFoundException) {
+ return false;
+ }
+ }
+
/* AuthorizationCodeInterface */
public function getAuthorizationCode($code)
{
- $code = $this->getObjectByType('code_table',$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, $code_challenge = null, $code_challenge_method = 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,
- 'code_challenge' => $code_challenge,
- 'code_challenge_method' => $code_challenge_method,
- ));
- } 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,
- 'code_challenge' => $code_challenge,
- 'code_challenge_method' => $code_challenge_method,
- ));
- }
+ $this->setObjectByType('code_table', $code, [
+ 'authorization_code' => $code,
+ 'client_id' => $client_id,
+ 'user_id' => $user_id,
+ 'redirect_uri' => $redirect_uri,
+ 'expires' => $expires,
+ 'scope' => $scope,
+ 'id_token' => $id_token,
+ 'code_challenge' => $code_challenge,
+ 'code_challenge_method' => $code_challenge_method,
+ ]);
return true;
}
public function expireAuthorizationCode($code)
{
- $this->deleteObjectByType('code_table',$code);
+ $this->deleteObjectByType('code_table', $code);
return true;
}
@@ -239,27 +238,27 @@ public function getUserDetails($username)
/* RefreshTokenInterface */
public function getRefreshToken($refresh_token)
{
- $token = $this->getObjectByType('refresh_token_table',$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(
+ $this->setObjectByType('refresh_token_table', $refresh_token, [
'refresh_token' => $refresh_token,
'client_id' => $client_id,
'user_id' => $user_id,
'expires' => $expires,
- 'scope' => $scope
- ));
+ 'scope' => $scope,
+ ]);
return true;
}
public function unsetRefreshToken($refresh_token)
{
- $this->deleteObjectByType('refresh_token_table',$refresh_token);
+ $this->deleteObjectByType('refresh_token_table', $refresh_token);
return true;
}
@@ -272,37 +271,26 @@ protected function checkPassword($user, $password)
public function getUser($username)
{
- $result = $this->getObjectByType('user_table',$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
- ));
-
- }
+ $this->setObjectByType('user_table', $username, [
+ '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)) {
+ if (!$jwt = $this->getObjectByType('jwt_table', $client_id)) {
return false;
}
diff --git a/src/OAuth2/Storage/DynamoDB.php b/src/OAuth2/Storage/DynamoDB.php
index 713189d23..eddbf7d72 100644
--- a/src/OAuth2/Storage/DynamoDB.php
+++ b/src/OAuth2/Storage/DynamoDB.php
@@ -3,6 +3,7 @@
namespace OAuth2\Storage;
use Aws\DynamoDb\DynamoDbClient;
+use Aws\DynamoDb\Marshaler;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
@@ -11,7 +12,7 @@
*
* To use, install "aws/aws-sdk-php" via composer
*
- * composer require aws/aws-sdk-php:dev-master
+ * composer require aws/aws-sdk-php:^3.0
*
*
* Once this is done, instantiate the DynamoDB client
@@ -45,25 +46,31 @@ class DynamoDB implements
{
protected $client;
protected $config;
+ protected $marshaler;
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');
+ throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance of DynamoDbClient or a configuration array containing 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');
+ throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance of DynamoDbClient or a configuration array containing key, secret, region');
}
- $this->client = DynamoDbClient::factory(array(
- 'key' => $connection["key"],
- 'secret' => $connection["secret"],
- 'region' =>$connection["region"]
+ $this->client = new DynamoDbClient(array(
+ 'credentials' => array(
+ 'key' => $connection["key"],
+ 'secret' => $connection["secret"],
+ ),
+ 'region' => $connection["region"],
+ 'version' => 'latest',
));
} else {
$this->client = $connection;
}
+ $this->marshaler = new Marshaler();
+
$this->config = array_merge(array(
'client_table' => 'oauth_clients',
'access_token_table' => 'oauth_access_tokens',
@@ -84,7 +91,7 @@ public function checkClientCredentials($client_id, $client_secret = null)
"Key" => array('client_id' => array('S' => $client_id))
));
- return $result->count()==1 && $result["Item"]["client_secret"]["S"] == $client_secret;
+ return isset($result["Item"]) && $result["Item"]["client_secret"]["S"] == $client_secret;
}
public function isPublicClient($client_id)
@@ -94,7 +101,7 @@ public function isPublicClient($client_id)
"Key" => array('client_id' => array('S' => $client_id))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
@@ -108,7 +115,7 @@ public function getClientDetails($client_id)
"TableName"=> $this->config['client_table'],
"Key" => array('client_id' => array('S' => $client_id))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$result = $this->dynamo2array($result);
@@ -124,11 +131,11 @@ public function getClientDetails($client_id)
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');
+ $clientData = array_filter($clientData, self::isNotEmpty(...));
- $result = $this->client->putItem(array(
+ $this->client->putItem(array(
'TableName' => $this->config['client_table'],
- 'Item' => $this->client->formatAttributes($clientData)
+ 'Item' => $this->marshaler->marshalItem($clientData)
));
return true;
@@ -154,7 +161,7 @@ public function getAccessToken($access_token)
"TableName"=> $this->config['access_token_table'],
"Key" => array('access_token' => array('S' => $access_token))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -171,11 +178,11 @@ public function setAccessToken($access_token, $client_id, $user_id, $expires, $s
$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');
+ $clientData = array_filter($clientData, self::isNotEmpty(...));
- $result = $this->client->putItem(array(
+ $this->client->putItem(array(
'TableName' => $this->config['access_token_table'],
- 'Item' => $this->client->formatAttributes($clientData)
+ 'Item' => $this->marshaler->marshalItem($clientData)
));
return true;
@@ -186,11 +193,11 @@ 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)),
+ 'Key' => array('access_token' => array('S' => $access_token)),
'ReturnValues' => 'ALL_OLD',
));
- return null !== $result->get('Attributes');
+ return !empty($result['Attributes']);
}
/* OAuth2\Storage\AuthorizationCodeInterface */
@@ -200,7 +207,7 @@ public function getAuthorizationCode($code)
"TableName"=> $this->config['code_table'],
"Key" => array('authorization_code' => array('S' => $code))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -219,11 +226,11 @@ public function setAuthorizationCode($authorization_code, $client_id, $user_id,
$expires = date('Y-m-d H:i:s', $expires);
$clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
+ $clientData = array_filter($clientData, self::isNotEmpty(...));
- $result = $this->client->putItem(array(
+ $this->client->putItem(array(
'TableName' => $this->config['code_table'],
- 'Item' => $this->client->formatAttributes($clientData)
+ 'Item' => $this->marshaler->marshalItem($clientData)
));
return true;
@@ -232,9 +239,9 @@ public function setAuthorizationCode($authorization_code, $client_id, $user_id,
public function expireAuthorizationCode($code)
{
- $result = $this->client->deleteItem(array(
+ $this->client->deleteItem(array(
'TableName' => $this->config['code_table'],
- 'Key' => $this->client->formatAttributes(array("authorization_code" => $code))
+ 'Key' => array('authorization_code' => array('S' => $code))
));
return true;
@@ -305,7 +312,7 @@ public function getRefreshToken($refresh_token)
"TableName"=> $this->config['refresh_token_table'],
"Key" => array('refresh_token' => array('S' => $refresh_token))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -320,11 +327,11 @@ public function setRefreshToken($refresh_token, $client_id, $user_id, $expires,
$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');
+ $clientData = array_filter($clientData, self::isNotEmpty(...));
- $result = $this->client->putItem(array(
+ $this->client->putItem(array(
'TableName' => $this->config['refresh_token_table'],
- 'Item' => $this->client->formatAttributes($clientData)
+ 'Item' => $this->marshaler->marshalItem($clientData)
));
return true;
@@ -332,9 +339,9 @@ public function setRefreshToken($refresh_token, $client_id, $user_id, $expires,
public function unsetRefreshToken($refresh_token)
{
- $result = $this->client->deleteItem(array(
+ $this->client->deleteItem(array(
'TableName' => $this->config['refresh_token_table'],
- 'Key' => $this->client->formatAttributes(array("refresh_token" => $refresh_token))
+ 'Key' => array('refresh_token' => array('S' => $refresh_token))
));
return true;
@@ -358,7 +365,7 @@ public function getUser($username)
"TableName"=> $this->config['user_table'],
"Key" => array('username' => array('S' => $username))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -373,11 +380,11 @@ public function setUser($username, $password, $first_name = null, $last_name = n
$password = $this->hashPassword($password);
$clientData = compact('username', 'password', 'first_name', 'last_name');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
+ $clientData = array_filter($clientData, self::isNotEmpty(...));
- $result = $this->client->putItem(array(
+ $this->client->putItem(array(
'TableName' => $this->config['user_table'],
- 'Item' => $this->client->formatAttributes($clientData)
+ 'Item' => $this->marshaler->marshalItem($clientData)
));
return true;
@@ -388,7 +395,6 @@ public function setUser($username, $password, $first_name = null, $last_name = n
public function scopeExists($scope)
{
$scope = explode(' ', $scope);
- $scope_query = array();
$count = 0;
foreach ($scope as $key => $val) {
$result = $this->client->query(array(
@@ -422,9 +428,8 @@ public function getDefaultScope($client_id = null)
)
));
$defaultScope = array();
- if ($result->count() > 0) {
- $array = $result->toArray();
- foreach ($array["Items"] as $item) {
+ if (($result['Count'] ?? 0) > 0) {
+ foreach ($result["Items"] as $item) {
$defaultScope[] = $item['scope']['S'];
}
@@ -441,7 +446,7 @@ public function getClientKey($client_id, $subject)
"TableName"=> $this->config['jwt_table'],
"Key" => array('client_id' => array('S' => $client_id), 'subject' => array('S' => $subject))
));
- if ($result->count()==0) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -475,12 +480,12 @@ public function setJti($client_id, $subject, $audience, $expires, $jti)
/* PublicKeyInterface */
public function getPublicKey($client_id = '0')
{
-
+ $client_id = $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) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -491,11 +496,12 @@ public function getPublicKey($client_id = '0')
public function getPrivateKey($client_id = '0')
{
+ $client_id = $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) {
+ if (!isset($result["Item"])) {
return false ;
}
$token = $this->dynamo2array($result);
@@ -505,11 +511,12 @@ public function getPrivateKey($client_id = '0')
public function getEncryptionAlgorithm($client_id = null)
{
+ $client_id = $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) {
+ if (!isset($result["Item"])) {
return 'RS256' ;
}
$token = $this->dynamo2array($result);
@@ -520,14 +527,13 @@ public function getEncryptionAlgorithm($client_id = null)
/**
* Transform dynamodb resultset to an array.
* @param $dynamodbResult
- * @return $array
+ * @return array
*/
private function dynamo2array($dynamodbResult)
{
$result = array();
foreach ($dynamodbResult["Item"] as $key => $val) {
$result[$key] = $val["S"];
- $result[] = $val["S"];
}
return $result;
@@ -537,4 +543,4 @@ private static function isNotEmpty($value)
{
return null !== $value && '' !== $value;
}
-}
\ No newline at end of file
+}
diff --git a/src/OAuth2/Storage/Memory.php b/src/OAuth2/Storage/Memory.php
index c33bd0ebb..b059ce200 100644
--- a/src/OAuth2/Storage/Memory.php
+++ b/src/OAuth2/Storage/Memory.php
@@ -112,7 +112,7 @@ public function setUser($username, $password, $firstName = null, $lastName = nul
public function getUserDetails($username)
{
- if (!isset($this->userCredentials[$username])) {
+ if (is_null($username) || !isset($this->userCredentials[$username])) {
return false;
}
@@ -339,7 +339,7 @@ public function setJti($client_id, $subject, $audience, $expires, $jti)
/*PublicKeyInterface */
public function getPublicKey($client_id = null)
{
- if (isset($this->keys[$client_id])) {
+ if (!is_null($client_id) && isset($this->keys[$client_id])) {
return $this->keys[$client_id]['public_key'];
}
@@ -353,7 +353,7 @@ public function getPublicKey($client_id = null)
public function getPrivateKey($client_id = null)
{
- if (isset($this->keys[$client_id])) {
+ if (!is_null($client_id) && isset($this->keys[$client_id])) {
return $this->keys[$client_id]['private_key'];
}
@@ -367,7 +367,7 @@ public function getPrivateKey($client_id = null)
public function getEncryptionAlgorithm($client_id = null)
{
- if (isset($this->keys[$client_id]['encryption_algorithm'])) {
+ if (!is_null($client_id) && isset($this->keys[$client_id]['encryption_algorithm'])) {
return $this->keys[$client_id]['encryption_algorithm'];
}
diff --git a/src/OAuth2/Storage/Mongo.php b/src/OAuth2/Storage/Mongo.php
deleted file mode 100644
index 92f93d5b2..000000000
--- a/src/OAuth2/Storage/Mongo.php
+++ /dev/null
@@ -1,396 +0,0 @@
-
- */
-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, $code_challenge = null, $code_challenge_method = 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,
- 'code_challenge' => $code_challenge,
- 'code_challenge_method' => $code_challenge_method,
- ))
- );
- } 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,
- 'code_challenge' => $code_challenge,
- 'code_challenge_method' => $code_challenge_method,
- );
- $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/src/OAuth2/Storage/Redis.php b/src/OAuth2/Storage/Redis.php
index 5a41dfc22..9b74798d4 100644
--- a/src/OAuth2/Storage/Redis.php
+++ b/src/OAuth2/Storage/Redis.php
@@ -79,7 +79,11 @@ protected function setValue($key, $value, $expire=0)
// 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';
+ if (is_bool($ret)) {
+ return $ret;
+ }
+
+ return (string) $ret === 'OK';
}
protected function expireValue($key)
diff --git a/stubs/couchbase.stub b/stubs/couchbase.stub
new file mode 100644
index 000000000..afb2034e1
--- /dev/null
+++ b/stubs/couchbase.stub
@@ -0,0 +1,47 @@
+getMemoryStorage();
$controller = new AuthorizeController($storage);
+ $this->assertInstanceOf('OAuth2\Controller\AuthorizeController', $controller);
}
private function getTestServer($config = array())
diff --git a/test/OAuth2/Controller/ResourceControllerTest.php b/test/OAuth2/Controller/ResourceControllerTest.php
index cd54d239a..5e362b564 100644
--- a/test/OAuth2/Controller/ResourceControllerTest.php
+++ b/test/OAuth2/Controller/ResourceControllerTest.php
@@ -162,6 +162,7 @@ public function testCreateController()
$storage = Bootstrap::getInstance()->getMemoryStorage();
$tokenType = new \OAuth2\TokenType\Bearer();
$controller = new ResourceController($tokenType, $storage);
+ $this->assertInstanceOf('OAuth2\Controller\ResourceController', $controller);
}
private function getTestServer($config = array())
diff --git a/test/OAuth2/Controller/TokenControllerTest.php b/test/OAuth2/Controller/TokenControllerTest.php
index d18eaa6d7..191e540e7 100644
--- a/test/OAuth2/Controller/TokenControllerTest.php
+++ b/test/OAuth2/Controller/TokenControllerTest.php
@@ -319,6 +319,7 @@ public function testCreateController()
$storage = Bootstrap::getInstance()->getMemoryStorage();
$accessToken = new \OAuth2\ResponseType\AccessToken($storage);
$controller = new TokenController($accessToken, $storage);
+ $this->assertInstanceOf('OAuth2\Controller\TokenController', $controller);
}
private function getTestServer()
diff --git a/test/OAuth2/Encryption/FirebaseJwtTest.php b/test/OAuth2/Encryption/FirebaseJwtTest.php
index 63a5d4036..0512c16dc 100644
--- a/test/OAuth2/Encryption/FirebaseJwtTest.php
+++ b/test/OAuth2/Encryption/FirebaseJwtTest.php
@@ -3,6 +3,7 @@
namespace OAuth2\Encryption;
use OAuth2\Storage\Bootstrap;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class FirebaseJwtTest extends TestCase
@@ -12,25 +13,38 @@ class FirebaseJwtTest extends TestCase
public function setUp(): void
{
$this->privateKey = <<assertFalse($jwtUtil->decode('go.o.b'));
}
- /** @dataProvider provideClientCredentials */
+ #[DataProvider('provideClientCredentials')]
public function testInvalidJwtHeader($client_id, $client_key)
{
$jwtUtil = new FirebaseJwt();
@@ -90,7 +104,7 @@ public function testInvalidJwtHeader($client_id, $client_key)
$this->assertFalse($payload);
}
- public function provideClientCredentials()
+ public static function provideClientCredentials()
{
$storage = Bootstrap::getInstance()->getMemoryStorage();
$client_id = 'Test Client ID';
diff --git a/test/OAuth2/Encryption/JwtTest.php b/test/OAuth2/Encryption/JwtTest.php
index 376a922b1..60ce8def8 100644
--- a/test/OAuth2/Encryption/JwtTest.php
+++ b/test/OAuth2/Encryption/JwtTest.php
@@ -3,6 +3,7 @@
namespace OAuth2\Encryption;
use OAuth2\Storage\Bootstrap;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class JwtTest extends TestCase
@@ -12,25 +13,38 @@ class JwtTest extends TestCase
public function setUp(): void
{
$this->privateKey = <<assertFalse($jwtUtil->decode('go.o.b'));
}
- /** @dataProvider provideClientCredentials */
+ #[DataProvider('provideClientCredentials')]
public function testInvalidJwtHeader($client_id, $client_key)
{
$jwtUtil = new Jwt();
@@ -90,7 +104,7 @@ public function testInvalidJwtHeader($client_id, $client_key)
$this->assertFalse($payload);
}
- public function provideClientCredentials()
+ public static function provideClientCredentials()
{
$storage = Bootstrap::getInstance()->getMemoryStorage();
$client_id = 'Test Client ID';
diff --git a/test/OAuth2/GrantType/JwtBearerTest.php b/test/OAuth2/GrantType/JwtBearerTest.php
index 4f6d67b2c..1c24a26c8 100644
--- a/test/OAuth2/GrantType/JwtBearerTest.php
+++ b/test/OAuth2/GrantType/JwtBearerTest.php
@@ -16,21 +16,34 @@ class JwtBearerTest extends TestCase
public function setUp(): void
{
$this->privateKey = <<assertEquals($code['id_token'], $new_id_token);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testRemoveIdTokenFromAuthorizationCode($storage)
{
// add new code
diff --git a/test/OAuth2/OpenID/Storage/UserClaimsTest.php b/test/OAuth2/OpenID/Storage/UserClaimsTest.php
index 840f6c566..da79ac5d5 100644
--- a/test/OAuth2/OpenID/Storage/UserClaimsTest.php
+++ b/test/OAuth2/OpenID/Storage/UserClaimsTest.php
@@ -4,10 +4,11 @@
use OAuth2\Storage\BaseTest;
use OAuth2\Storage\NullStorage;
+use PHPUnit\Framework\Attributes\DataProvider;
class UserClaimsTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetUserClaims($storage)
{
if ($storage instanceof NullStorage) {
@@ -17,7 +18,8 @@ public function testGetUserClaims($storage)
}
if (!$storage instanceof UserClaimsInterface) {
- // incompatible storage
+ $this->markTestSkipped('Incompatible storage: UserClaimsInterface required');
+
return;
}
diff --git a/test/OAuth2/ServerTest.php b/test/OAuth2/ServerTest.php
index fab526a6f..36ffd1af7 100644
--- a/test/OAuth2/ServerTest.php
+++ b/test/OAuth2/ServerTest.php
@@ -6,11 +6,9 @@
use OAuth2\ResponseType\AuthorizationCode;
use OAuth2\Storage\Bootstrap;
use PHPUnit\Framework\TestCase;
-use Yoast\PHPUnitPolyfills\Polyfills\ExpectPHPException;
class ServerTest extends TestCase
{
- use ExpectPHPException;
public function testGetAuthorizeControllerWithNoClientStorageThrowsException()
{
@@ -108,7 +106,7 @@ public function testGetTokenControllerWithAccessTokenAndClientCredentialsStorage
$server = new Server();
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
- $server->getTokenController();
+ $this->assertNotNull($server->getTokenController());
}
public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStorageAndGrantTypes()
@@ -117,7 +115,7 @@ public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStor
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addGrantType($this->createMock('OAuth2\GrantType\AuthorizationCode'));
- $server->getTokenController();
+ $this->assertNotNull($server->getTokenController());
}
public function testGetResourceControllerWithNoAccessTokenStorageThrowsException()
@@ -131,7 +129,7 @@ public function testGetResourceControllerWithAccessTokenStorage()
{
$server = new Server();
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
- $server->getResourceController();
+ $this->assertNotNull($server->getResourceController());
}
public function testAddingStorageWithInvalidClass()
@@ -162,7 +160,7 @@ public function testAddingStorageWithValidKeyOnlySetsThatKey()
$reflection = new \ReflectionClass($server);
$prop = $reflection->getProperty('storages');
- $prop->setAccessible(true);
+
$storages = $prop->getValue($server); // get the private "storages" property
@@ -252,11 +250,11 @@ public function testAddingResponseType()
$storage
->expects($this->any())
->method('getClientDetails')
- ->will($this->returnValue(array('client_id' => 'some_client')));
+ ->willReturn(array('client_id' => 'some_client'));
$storage
->expects($this->any())
->method('checkRestrictedGrantType')
- ->will($this->returnValue(true));
+ ->willReturn(true);
// add with the "code" key explicitly set
$codeType = new AuthorizationCode($storage);
@@ -309,11 +307,11 @@ public function testCustomClientAssertionType()
$clientAssertionType
->expects($this->once())
->method('validateRequest')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$clientAssertionType
->expects($this->once())
->method('getClientId')
- ->will($this->returnValue('Test Client ID'));
+ ->willReturn('Test Client ID');
// create mock storage
$storage = Bootstrap::getInstance()->getMemoryStorage();
@@ -334,7 +332,7 @@ public function testHttpBasicConfig()
$reflection = new \ReflectionClass($httpBasic);
$prop = $reflection->getProperty('config');
- $prop->setAccessible(true);
+
$config = $prop->getValue($httpBasic); // get the private "config" property
@@ -357,11 +355,11 @@ public function testRefreshTokenConfig()
$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);
@@ -503,7 +501,7 @@ public function testUsingOpenIDConnectWithIssuerPublicKeyAndUserClaimsIsOkay()
public function testUsingOpenIDConnectWithAllowImplicitWithoutTokenStorageThrowsException()
{
- $this->expectErrorMessage('OAuth2\ResponseType\AccessTokenInterface');
+ $this->expectExceptionMessage('OAuth2\ResponseType\AccessTokenInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
@@ -581,7 +579,7 @@ public function testUsingOpenIDConnectWithAuthorizationCodeStorageThrowsExceptio
$token = $this->createMock('OAuth2\Storage\AccessTokenInterface');
$authcode = $this->createMock('OAuth2\Storage\AuthorizationCodeInterface');
- $this->expectErrorMessage('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
+ $this->expectExceptionMessage('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
$server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array(
'use_openid_connect' => true,
'issuer' => 'someguy'
diff --git a/test/OAuth2/Storage/AccessTokenTest.php b/test/OAuth2/Storage/AccessTokenTest.php
index b34e0bfc0..9fccee844 100644
--- a/test/OAuth2/Storage/AccessTokenTest.php
+++ b/test/OAuth2/Storage/AccessTokenTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class AccessTokenTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSetAccessToken(AccessTokenInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -55,15 +57,21 @@ public function testSetAccessToken(AccessTokenInterface $storage)
$this->assertTrue($success);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testUnsetAccessToken(AccessTokenInterface $storage)
{
- if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) {
+ if ($storage instanceof NullStorage) {
$this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
return;
}
+ if (!method_exists($storage, 'unsetAccessToken')) {
+ $this->markTestSkipped('Skipped Storage: unsetAccessToken not implemented');
+
+ return;
+ }
+
// assert token we are about to unset does not exist
$token = $storage->getAccessToken('revokabletoken');
$this->assertFalse($token);
@@ -82,15 +90,21 @@ public function testUnsetAccessToken(AccessTokenInterface $storage)
$this->assertFalse($token);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testUnsetAccessTokenReturnsFalse(AccessTokenInterface $storage)
{
- if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) {
+ if ($storage instanceof NullStorage) {
$this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
return;
}
+ if (!method_exists($storage, 'unsetAccessToken')) {
+ $this->markTestSkipped('Skipped Storage: unsetAccessToken not implemented');
+
+ return;
+ }
+
// assert token we are about to unset does not exist
$token = $storage->getAccessToken('nonexistanttoken');
$this->assertFalse($token);
diff --git a/test/OAuth2/Storage/AuthorizationCodeTest.php b/test/OAuth2/Storage/AuthorizationCodeTest.php
index 2d901b501..9fb015387 100644
--- a/test/OAuth2/Storage/AuthorizationCodeTest.php
+++ b/test/OAuth2/Storage/AuthorizationCodeTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class AuthorizationCodeTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetAuthorizationCode(AuthorizationCodeInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -22,7 +24,7 @@ public function testGetAuthorizationCode(AuthorizationCodeInterface $storage)
$this->assertNotNull($details);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSetAuthorizationCode(AuthorizationCodeInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -77,7 +79,7 @@ public function testSetAuthorizationCode(AuthorizationCodeInterface $storage)
$this->assertTrue($success);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testExpireAccessToken(AccessTokenInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/OAuth2/Storage/ClientCredentialsTest.php b/test/OAuth2/Storage/ClientCredentialsTest.php
index 15289af30..af8f973c4 100644
--- a/test/OAuth2/Storage/ClientCredentialsTest.php
+++ b/test/OAuth2/Storage/ClientCredentialsTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class ClientCredentialsTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testCheckClientCredentials(ClientCredentialsInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/OAuth2/Storage/ClientTest.php b/test/OAuth2/Storage/ClientTest.php
index 6a5cc0b49..2a97ca739 100644
--- a/test/OAuth2/Storage/ClientTest.php
+++ b/test/OAuth2/Storage/ClientTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class ClientTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetClientDetails(ClientInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -25,7 +27,7 @@ public function testGetClientDetails(ClientInterface $storage)
$this->assertArrayHasKey('redirect_uri', $details);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testCheckRestrictedGrantType(ClientInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -43,7 +45,7 @@ public function testCheckRestrictedGrantType(ClientInterface $storage)
$this->assertTrue($pass);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetAccessToken(ClientInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -61,7 +63,7 @@ public function testGetAccessToken(ClientInterface $storage)
$this->assertNotNull($details);
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testIsPublicClient(ClientInterface $storage)
{
if ($storage instanceof NullStorage) {
@@ -84,7 +86,7 @@ public function testIsPublicClient(ClientInterface $storage)
$this->assertFalse($storage->isPublicClient($confidentialClientId));
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSaveClient(ClientInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/OAuth2/Storage/DynamoDBTest.php b/test/OAuth2/Storage/DynamoDBTest.php
index 2147f0914..cc58345b3 100644
--- a/test/OAuth2/Storage/DynamoDBTest.php
+++ b/test/OAuth2/Storage/DynamoDBTest.php
@@ -2,37 +2,27 @@
namespace OAuth2\Storage;
+use Aws\Result;
+
class DynamoDBTest extends BaseTest
{
public function testGetDefaultScope()
{
$client = $this->getMockBuilder('\Aws\DynamoDb\DynamoDbClient')
->disableOriginalConstructor()
- ->setMethods(array('query'))
- ->getMock();
-
- $return = $this->getMockBuilder('\Guzzle\Service\Resource\Model')
- ->setMethods(array('count', 'toArray'))
+ ->addMethods(array('query'))
->getMock();
- $data = array(
+ $data = new Result(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));
+ ->willReturn($data);
$storage = new DynamoDB($client);
$this->assertNull($storage->getDefaultScope());
diff --git a/test/OAuth2/Storage/JwtAccessTokenTest.php b/test/OAuth2/Storage/JwtAccessTokenTest.php
index a6acbea1f..afa460c3f 100644
--- a/test/OAuth2/Storage/JwtAccessTokenTest.php
+++ b/test/OAuth2/Storage/JwtAccessTokenTest.php
@@ -3,14 +3,22 @@
namespace OAuth2\Storage;
use OAuth2\Encryption\Jwt;
+use PHPUnit\Framework\Attributes\DataProvider;
class JwtAccessTokenTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSetAccessToken($storage)
{
- if (!$storage instanceof PublicKey) {
- // incompatible storage
+ if ($storage instanceof NullStorage) {
+ $this->markTestSkipped("Skipped Storage: {$storage}");
+
+ return;
+ }
+
+ if (!$storage instanceof PublicKeyInterface) {
+ $this->markTestSkipped('Incompatible storage: PublicKeyInterface required');
+
return;
}
diff --git a/test/OAuth2/Storage/JwtBearerTest.php b/test/OAuth2/Storage/JwtBearerTest.php
index d0ab9b899..880b3b650 100644
--- a/test/OAuth2/Storage/JwtBearerTest.php
+++ b/test/OAuth2/Storage/JwtBearerTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class JwtBearerTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetClientKey(JwtBearerInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/OAuth2/Storage/PdoTest.php b/test/OAuth2/Storage/PdoTest.php
index 9a7630423..e269bc2d0 100644
--- a/test/OAuth2/Storage/PdoTest.php
+++ b/test/OAuth2/Storage/PdoTest.php
@@ -2,11 +2,8 @@
namespace OAuth2\Storage;
-use Yoast\PHPUnitPolyfills\Polyfills\ExpectPHPException;
-
class PdoTest extends BaseTest
{
- use ExpectPHPException;
public function testCreatePdoStorageUsingPdoClass()
{
@@ -36,7 +33,7 @@ public function testCreatePdoStorageUsingConfig()
public function testCreatePdoStorageWithoutDSNThrowsException()
{
- $this->expectErrorMessage('dsn');
+ $this->expectExceptionMessage('dsn');
$config = array('username' => 'brent', 'password' => 'brentisaballer');
$storage = new Pdo($config);
}
diff --git a/test/OAuth2/Storage/PublicKeyTest.php b/test/OAuth2/Storage/PublicKeyTest.php
index f85195870..db2ff9c3d 100644
--- a/test/OAuth2/Storage/PublicKeyTest.php
+++ b/test/OAuth2/Storage/PublicKeyTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class PublicKeyTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSetAccessToken($storage)
{
if ($storage instanceof NullStorage) {
@@ -14,7 +16,8 @@ public function testSetAccessToken($storage)
}
if (!$storage instanceof PublicKeyInterface) {
- // incompatible storage
+ $this->markTestSkipped('Incompatible storage: PublicKeyInterface required');
+
return;
}
diff --git a/test/OAuth2/Storage/RefreshTokenTest.php b/test/OAuth2/Storage/RefreshTokenTest.php
index 314c93195..e4172d5ff 100644
--- a/test/OAuth2/Storage/RefreshTokenTest.php
+++ b/test/OAuth2/Storage/RefreshTokenTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class RefreshTokenTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testSetRefreshToken(RefreshTokenInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/OAuth2/Storage/ScopeTest.php b/test/OAuth2/Storage/ScopeTest.php
index fd1edeb93..97f1faa33 100644
--- a/test/OAuth2/Storage/ScopeTest.php
+++ b/test/OAuth2/Storage/ScopeTest.php
@@ -3,10 +3,11 @@
namespace OAuth2\Storage;
use OAuth2\Scope;
+use PHPUnit\Framework\Attributes\DataProvider;
class ScopeTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testScopeExists($storage)
{
if ($storage instanceof NullStorage) {
@@ -16,7 +17,8 @@ public function testScopeExists($storage)
}
if (!$storage instanceof ScopeInterface) {
- // incompatible storage
+ $this->markTestSkipped('Incompatible storage: ScopeInterface required');
+
return;
}
@@ -28,7 +30,7 @@ public function testScopeExists($storage)
$this->assertFalse($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3 fakescope'));
}
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testGetDefaultScope($storage)
{
if ($storage instanceof NullStorage) {
@@ -38,7 +40,8 @@ public function testGetDefaultScope($storage)
}
if (!$storage instanceof ScopeInterface) {
- // incompatible storage
+ $this->markTestSkipped('Incompatible storage: ScopeInterface required');
+
return;
}
diff --git a/test/OAuth2/Storage/UserCredentialsTest.php b/test/OAuth2/Storage/UserCredentialsTest.php
index 65655a6b2..fad3b15f4 100644
--- a/test/OAuth2/Storage/UserCredentialsTest.php
+++ b/test/OAuth2/Storage/UserCredentialsTest.php
@@ -2,9 +2,11 @@
namespace OAuth2\Storage;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class UserCredentialsTest extends BaseTest
{
- /** @dataProvider provideStorage */
+ #[DataProvider('provideStorage')]
public function testCheckUserCredentials(UserCredentialsInterface $storage)
{
if ($storage instanceof NullStorage) {
diff --git a/test/config/storage.json b/test/config/storage.json
index 52d3f2399..c56118a56 100644
--- a/test/config/storage.json
+++ b/test/config/storage.json
@@ -140,7 +140,7 @@
},
"jwt": {
"Test Client ID": {
- "key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/SxVlE8gnpFqCxgl2wjhzY7u\ncEi00s0kUg3xp7lVEvgLgYcAnHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1o\nwR0p4d9pOaJK07d01+RzoQLOIQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8\nUlvdRKBxriRnlP3qJQIDAQAB\n-----END PUBLIC KEY-----",
+ "key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvryKBogPyv5P8jYRdZKb\n88Eg+gBul1FF5vkftzsVCFu8BvM5p64w5N4cAK6Rv/62MXRBi+sIhfIQ682C0rK9\nX8kbJLlu6QluvofB1r2qB5AIf8lOzJlzKlMgHN4qP4VcdB93QeyVmyL1dADPG5hI\npPgyP3gMW+a7QVr1BEfzqT26vNZm4e0n0v+9iG1W+Q9zjFIjQz1/+BM+F8yIMK74\n7Fpz+sMYLllLAJdElnTghT8E+3am6bVVDcHRKBpGeIz5f8ncVbWwHWwRqNjEVRUT\nBxXkLVQw4s4gvU+HgJHkhIhbwh+vEDpU1oY85ajO6NRuHqZbUPNc4rAccBSyJ+ze\nIQIDAQAB\n-----END PUBLIC KEY-----",
"subject": "testuser@ourdomain.com"
},
"Test Client ID PHP-5.2": {
diff --git a/test/lib/OAuth2/Storage/BaseTest.php b/test/lib/OAuth2/Storage/BaseTest.php
index e841d3ad2..9d236c012 100755
--- a/test/lib/OAuth2/Storage/BaseTest.php
+++ b/test/lib/OAuth2/Storage/BaseTest.php
@@ -6,13 +6,12 @@
abstract class BaseTest extends TestCase
{
- public function provideStorage()
+ public static function provideStorage()
{
$memory = Bootstrap::getInstance()->getMemoryStorage();
$sqlite = Bootstrap::getInstance()->getSqlitePdo();
$mysql = Bootstrap::getInstance()->getMysqlPdo();
$postgres = Bootstrap::getInstance()->getPostgresPdo();
- $mongo = Bootstrap::getInstance()->getMongo();
$mongoDb = Bootstrap::getInstance()->getMongoDB();
$redis = Bootstrap::getInstance()->getRedisStorage();
$cassandra = Bootstrap::getInstance()->getCassandraStorage();
@@ -27,7 +26,6 @@ public function provideStorage()
array($sqlite),
array($mysql),
array($postgres),
- array($mongo),
array($mongoDb),
array($redis),
array($cassandra),
diff --git a/test/lib/OAuth2/Storage/Bootstrap.php b/test/lib/OAuth2/Storage/Bootstrap.php
index 66c93ae5b..724b1dbef 100755
--- a/test/lib/OAuth2/Storage/Bootstrap.php
+++ b/test/lib/OAuth2/Storage/Bootstrap.php
@@ -4,13 +4,10 @@
class Bootstrap
{
- const DYNAMODB_PHP_VERSION = 'none';
-
protected static $instance;
private $mysql;
private $sqlite;
private $postgres;
- private $mongo;
private $mongoDb;
private $redis;
private $cassandra;
@@ -68,7 +65,8 @@ public function getPostgresPdo()
public function getPostgresDriver()
{
try {
- $pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres', 'postgres');
+ $pgHost = $this->getEnvVar('POSTGRES_HOST', 'localhost');
+ $pdo = new \PDO("pgsql:host={$pgHost};dbname=oauth2_server_php", 'postgres', 'postgres');
return $pdo;
} catch (\PDOException $e) {
@@ -85,7 +83,8 @@ public function getRedisStorage()
{
if (!$this->redis) {
if (class_exists('Predis\Client')) {
- $redis = new \Predis\Client();
+ $redisHost = $this->getEnvVar('REDIS_HOST', '127.0.0.1');
+ $redis = new \Predis\Client(['host' => $redisHost]);
if ($this->testRedisConnection($redis)) {
$redis->flushdb();
$this->redis = new Redis($redis);
@@ -118,9 +117,10 @@ public function getMysqlPdo()
if (!$this->mysql) {
$pdo = null;
try {
- $pdo = new \PDO('mysql:host=localhost;', 'root', 'root');
+ $mysqlHost = $this->getEnvVar('MYSQL_HOST', '127.0.0.1');
+ $pdo = new \PDO("mysql:host={$mysqlHost};", 'root', 'root');
} catch (\PDOException $e) {
- $this->mysql = new NullStorage('MySQL', 'Unable to connect to MySQL on root@localhost');
+ $this->mysql = new NullStorage('MySQL', "Unable to connect to MySQL on root@{$mysqlHost}");
}
if ($pdo) {
@@ -135,33 +135,12 @@ public function getMysqlPdo()
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 (extension_loaded('mongodb') && class_exists('MongoDB\Client')) {
+ $mongoHost = $this->getEnvVar('MONGODB_HOST', 'localhost');
+ $mongoDb = new \MongoDB\Client("mongodb://{$mongoHost}:27017");
if ($this->testMongoDBConnection($mongoDb)) {
$db = $mongoDb->oauth2_server_php;
$this->removeMongoDb($db);
@@ -179,17 +158,6 @@ public function getMongoDb()
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;
@@ -200,103 +168,73 @@ 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');
+ } elseif (!extension_loaded('couchbase') || !class_exists(\Couchbase\ClusterOptions::class)) {
+ $this->couchbase = new NullStorage('Couchbase', 'Missing Couchbase SDK. Install ext-couchbase and couchbase/couchbase ^4.4');
} 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');
- }
- }
- }
+ try {
+ $options = new \Couchbase\ClusterOptions();
+ $options->credentials(
+ $this->getEnvVar('CB_USERNAME', 'Administrator'),
+ $this->getEnvVar('CB_PASSWORD', 'password')
+ );
+ $cluster = new \Couchbase\Cluster(
+ $this->getEnvVar('CB_CONNECTION_STRING', 'couchbase://localhost'),
+ $options
+ );
+ $bucket = $cluster->bucket($this->getEnvVar('CB_BUCKET', 'default'));
+ $collection = $bucket->defaultCollection();
- return $this->couchbase;
- }
+ $this->clearCouchbase($collection);
+ $this->createCouchbaseDB($collection);
- private function testCouchbaseConnection(\Couchbase $couchbase)
- {
- try {
- if (count($couchbase->getServers()) > 0) {
- return true;
+ $this->couchbase = new CouchbaseDB($collection);
+ } catch (\Exception $e) {
+ $this->couchbase = new NullStorage('Couchbase', 'Unable to connect to Couchbase: ' . $e->getMessage());
+ }
}
- } catch (\CouchbaseException $e) {
- return false;
}
- return true;
+ return $this->couchbase;
}
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"');
- }
- }
+ if (!class_exists('Cassandra\Connection')) {
+ $this->cassandra = new NullStorage('Cassandra', 'Missing cassandra library. Please run "composer require mroosz/php-cassandra"');
- return $this->cassandra;
- }
+ return $this->cassandra;
+ }
- private function testCassandraConnection(\phpcassa\Connection\ConnectionPool $cassandra)
- {
- try {
- new \phpcassa\SystemManager('localhost:9160');
- } catch (\Exception $e) {
- return false;
+ try {
+ $cassandraHost = $this->getEnvVar('CASSANDRA_HOST', '127.0.0.1');
+ $conn = new \Cassandra\Connection([
+ new \Cassandra\Connection\StreamNodeConfig(
+ host: $cassandraHost,
+ port: 9042,
+ ),
+ ]);
+ $conn->connect();
+
+ // recreate keyspace
+ $conn->query("DROP KEYSPACE IF EXISTS oauth2_test");
+ $conn->query("CREATE KEYSPACE oauth2_test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}");
+ $conn->query("CREATE TABLE oauth2_test.oauth_data (key text PRIMARY KEY, value text)");
+
+ $conn->setKeyspace('oauth2_test');
+
+ $this->cassandra = new Cassandra($conn);
+ $this->createCassandraDb($this->cassandra, $conn);
+ } catch (\Exception $e) {
+ $this->cassandra = new NullStorage('Cassandra', $e->getMessage());
+ }
}
- return true;
- }
-
- private function removeCassandraDb()
- {
- $sys = new \phpcassa\SystemManager('localhost:9160');
-
- try {
- $sys->drop_keyspace('oauth2_test');
- } catch (\cassandra\InvalidRequestException $e) {
-
- }
+ return $this->cassandra;
}
- private function createCassandraDb(Cassandra $storage)
+ private function createCassandraDb(Cassandra $storage, \Cassandra\Connection $conn)
{
- // 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);
@@ -318,12 +256,24 @@ private function createCassandraDb(Cassandra $storage)
$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))));
-
+ // insert public keys and user directly
+ $table = 'oauth_data';
+ $conn->query("INSERT INTO $table (key, value) VALUES (?, ?)", [
+ 'oauth_public_keys:ClientID_One',
+ json_encode(array("public_key" => "client_1_public", "private_key" => "client_1_private", "encryption_algorithm" => "RS256")),
+ ]);
+ $conn->query("INSERT INTO $table (key, value) VALUES (?, ?)", [
+ 'oauth_public_keys:ClientID_Two',
+ json_encode(array("public_key" => "client_2_public", "private_key" => "client_2_private", "encryption_algorithm" => "RS256")),
+ ]);
+ $conn->query("INSERT INTO $table (key, value) VALUES (?, ?)", [
+ 'oauth_public_keys:',
+ json_encode(array("public_key" => $this->getTestPublicKey(), "private_key" => $this->getTestPrivateKey(), "encryption_algorithm" => "RS256")),
+ ]);
+ $conn->query("INSERT INTO $table (key, value) VALUES (?, ?)", [
+ 'oauth_users:testuser',
+ json_encode(array("password" => "password", "email" => "testuser@test.com", "email_verified" => true)),
+ ]);
}
private function createSqliteDb(\PDO $pdo)
@@ -352,11 +302,17 @@ private function removeMysqlDb(\PDO $pdo)
private function createPostgresDb()
{
- if (!`PGPASSWORD=postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'" -h localhost -U postgres`) {
- `PGPASSWORD=postgres createuser -s -r postgres -h localhost -U postgres`;
+ try {
+ $pgHost = $this->getEnvVar('POSTGRES_HOST', 'localhost');
+ $pdo = new \PDO("pgsql:host={$pgHost}", 'postgres', 'postgres');
+ $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ $exists = $pdo->query("SELECT 1 FROM pg_database WHERE datname = 'oauth2_server_php'")->fetchColumn();
+ if (!$exists) {
+ $pdo->exec('CREATE DATABASE oauth2_server_php');
+ }
+ } catch (\PDOException $e) {
+ // connection failed — will be caught later in getPostgresPdo
}
-
- `PGPASSWORD=postgres createdb -O postgres oauth2_server_php -h localhost -U postgres`;
}
private function populatePostgresDb(\PDO $pdo)
@@ -366,8 +322,15 @@ private function populatePostgresDb(\PDO $pdo)
private function removePostgresDb()
{
- if (trim(`PGPASSWORD=postgres psql -l -h localhost -U postgres | grep oauth2_server_php | wc -l`)) {
- `PGPASSWORD=postgres dropdb oauth2_server_php -h localhost -U postgres`;
+ try {
+ $pgHost = $this->getEnvVar('POSTGRES_HOST', 'localhost');
+ $pdo = new \PDO("pgsql:host={$pgHost}", 'postgres', 'postgres');
+ $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ // terminate existing connections before dropping
+ $pdo->exec("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'oauth2_server_php' AND pid <> pg_backend_pid()");
+ $pdo->exec('DROP DATABASE IF EXISTS oauth2_server_php');
+ } catch (\PDOException $e) {
+ // connection failed — will be caught later
}
}
@@ -428,90 +391,54 @@ public function getConfigDir()
return $this->configDir;
}
- private function createCouchbaseDB(\Couchbase $db)
+ private function createCouchbaseDB(\Couchbase\Collection $collection)
{
- $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(
+ $collection->upsert('oauth_clients-oauth_test_client', [
'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(
+ 'client_secret' => 'testpass',
+ 'redirect_uri' => 'http://example.com',
+ 'grant_types' => 'implicit password',
+ ]);
+
+ $collection->upsert('oauth_access_tokens-testtoken', [
+ 'access_token' => 'testtoken',
+ 'client_id' => 'Some Client',
+ ]);
+
+ $collection->upsert('oauth_authorization_codes-testcode', [
+ 'access_token' => 'testcode',
+ 'client_id' => 'Some Client',
+ ]);
+
+ $collection->upsert('oauth_users-testuser', [
'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(
+ $collection->upsert('oauth_jwt-oauth_test_client', [
'client_id' => 'oauth_test_client',
'key' => $this->getTestPublicKey(),
- 'subject' => 'test_subject',
- ));
+ 'subject' => 'test_subject',
+ ]);
}
- public function removeMongo(\MongoDB $db)
+ private function clearCouchbase(\Couchbase\Collection $collection)
{
- $db->drop();
+ $keys = [
+ 'oauth_authorization_codes-new-openid-code',
+ 'oauth_access_tokens-newtoken',
+ 'oauth_authorization_codes-newcode',
+ 'oauth_refresh_tokens-refreshtoken',
+ ];
+ foreach ($keys as $key) {
+ try {
+ $collection->remove($key);
+ } catch (\Couchbase\Exception\DocumentNotFoundException) {
+ // ignore
+ }
+ }
}
private function createMongoDB(\MongoDB\Database $db)
@@ -597,223 +524,167 @@ private function getTestPrivateKey()
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');
+ try {
+ $this->initDynamoDbStorage();
+ } catch (\Exception $e) {
+ $this->dynamodb = new NullStorage('DynamoDb', $e->getMessage());
}
}
return $this->dynamodb;
}
- private function getDynamoDbClient()
+ private function initDynamoDbStorage()
{
- $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');
+ if (!class_exists('\Aws\DynamoDb\DynamoDbClient')) {
+ $this->dynamodb = new NullStorage('DynamoDb', 'Missing DynamoDB library. Please run "composer require aws/aws-sdk-php:^3.0"');
- return;
- }
+ return;
+ }
+
+ $endpoint = $this->getEnvVar('DYNAMODB_ENDPOINT', 'http://localhost:8000');
+
+ try {
+ $client = new \Aws\DynamoDb\DynamoDbClient([
+ 'region' => 'us-east-1',
+ 'version' => 'latest',
+ 'endpoint' => $endpoint,
+ 'credentials' => [
+ 'key' => 'fake',
+ 'secret' => 'fake',
+ ],
+ ]);
+
+ // verify DynamoDB Local is reachable
+ $client->listTables();
+ } catch (\Exception $e) {
+ $this->dynamodb = new NullStorage('DynamoDb', 'Unable to connect to DynamoDB Local at ' . $endpoint . ': ' . $e->getMessage());
- // set profile in AWS_PROFILE environment variable, defaults to "default"
- $config['profile'] = $this->getEnvVar('AWS_PROFILE', 'default');
+ return;
}
- // 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);
+ $prefix = 'test_';
+ $this->deleteDynamoDb($client, $prefix);
+ $this->createDynamoDb($client, $prefix);
+ $this->populateDynamoDb($client, $prefix);
- return \Aws\DynamoDb\DynamoDbClient::factory($config);
+ $config = [
+ '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);
}
- private function deleteDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null, $waitForDeletion = false)
+ private function deleteDynamoDb(\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);
- // Delete all table.
- foreach ($tablesList as $key => $table) {
+ foreach ($tablesList as $table) {
try {
- $client->deleteTable(array('TableName' => $prefix.$table));
+ $client->deleteTable(['TableName' => $prefix.$table]);
+ $client->waitUntil('TableNotExists', ['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--;
- }
+ // Table does not exist
}
}
-
- 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(
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'access_token', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'access_token', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'authorization_code', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'authorization_code', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'client_id', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'client_id', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'client_id', 'AttributeType' => 'S'],
+ ['AttributeName' => 'subject', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [
+ ['AttributeName' => 'client_id', 'KeyType' => 'HASH'],
+ ['AttributeName' => 'subject', 'KeyType' => 'RANGE'],
+ ],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'client_id', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'client_id', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'refresh_token', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'refresh_token', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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(
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'scope', 'AttributeType' => 'S'],
+ ['AttributeName' => 'is_default', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'scope', 'KeyType' => 'HASH']],
+ 'GlobalSecondaryIndexes' => [
+ [
'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(
+ 'KeySchema' => [['AttributeName' => 'is_default', 'KeyType' => 'HASH']],
+ 'Projection' => ['ProjectionType' => 'ALL'],
+ ],
+ ],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ $client->createTable([
'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);
- }
+ 'AttributeDefinitions' => [
+ ['AttributeName' => 'username', 'AttributeType' => 'S'],
+ ],
+ 'KeySchema' => [['AttributeName' => 'username', 'KeyType' => 'HASH']],
+ 'BillingMode' => 'PAY_PER_REQUEST',
+ ]);
+
+ // Wait for all tables to become active
+ $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users');
+ foreach ($tablesList as $table) {
+ $client->waitUntil('TableExists', ['TableName' => $prefix.$table]);
}
}