Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion to create base class for key-value storages 2 #697

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
472 changes: 45 additions & 427 deletions src/OAuth2/Storage/Cassandra.php

Large diffs are not rendered by default.

322 changes: 16 additions & 306 deletions src/OAuth2/Storage/CouchbaseDB.php
Original file line number Diff line number Diff line change
@@ -1,331 +1,41 @@
<?php

namespace OAuth2\Storage;

use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;

/**
* Simple Couchbase storage for all storage types
*
* This class should be extended or overridden as required
*
* NOTE: Passwords are stored in plaintext, which is never
* a good idea. Be sure to override this for your application
*
* @author Tom Park <tom@raucter.com>
*/
class CouchbaseDB implements AuthorizationCodeInterface,
AccessTokenInterface,
ClientCredentialsInterface,
UserCredentialsInterface,
RefreshTokenInterface,
JwtBearerInterface,
OpenIDAuthorizationCodeInterface
class CouchbaseDB extends KeyValueAbstract
{

protected $db;
protected $config;

public function __construct($connection, $config = array())
public function __construct($connection, array $config = array())
{
if ($connection instanceof \Couchbase) {
$this->db = $connection;
} elseif (is_array($connection) && isset($connection['servers']) && is_array($connection['servers'])) {
$this->db = new \Couchbase($connection['servers'], (isset($connection['username']) ? $connection['username'] : ''), (isset($connection['password']) ? $connection['password'] : ''), (isset($connection['bucket']) ? $connection['bucket'] : 'default'), false);
} else {
if (!is_array($connection) || !is_array($connection['servers'])) {
throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array');
}

$this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
}

$this->config = array_merge(array(
'client_table' => 'oauth_clients',
'access_token_table' => 'oauth_access_tokens',
'refresh_token_table' => 'oauth_refresh_tokens',
'code_table' => 'oauth_authorization_codes',
'user_table' => 'oauth_users',
'jwt_table' => 'oauth_jwt',
), $config);
}

// Helper function to access couchbase item by type:
protected function getObjectByType($name,$id)
{
return json_decode($this->db->get($this->config[$name].'-'.$id),true);
}

// Helper function to set couchbase item by type:
protected function setObjectByType($name,$id,$array)
{
$array['type'] = $name;

return $this->db->set($this->config[$name].'-'.$id,json_encode($array));
}

// Helper function to delete couchbase item by type, wait for persist to at least 1 node
protected function deleteObjectByType($name,$id)
{
$this->db->delete($this->config[$name].'-'.$id,"",1);
}

/* ClientCredentialsInterface */
public function checkClientCredentials($client_id, $client_secret = null)
{
if ($result = $this->getObjectByType('client_table',$client_id)) {
return $result['client_secret'] == $client_secret;
}

return false;
}

public function isPublicClient($client_id)
{
if (!$result = $this->getObjectByType('client_table',$client_id)) {
return false;
}

return empty($result['client_secret']);
}

/* ClientInterface */
public function getClientDetails($client_id)
{
$result = $this->getObjectByType('client_table',$client_id);

return is_null($result) ? false : $result;
}

public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{
if ($this->getClientDetails($client_id)) {

$this->setObjectByType('client_table',$client_id, array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'redirect_uri' => $redirect_uri,
'grant_types' => $grant_types,
'scope' => $scope,
'user_id' => $user_id,
));
} else {
$this->setObjectByType('client_table',$client_id, array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'redirect_uri' => $redirect_uri,
'grant_types' => $grant_types,
'scope' => $scope,
'user_id' => $user_id,
));
}

return true;
}

public function checkRestrictedGrantType($client_id, $grant_type)
{
$details = $this->getClientDetails($client_id);
if (isset($details['grant_types'])) {
$grant_types = explode(' ', $details['grant_types']);

return in_array($grant_type, $grant_types);
}

// if grant_types are not defined, then none are restricted
return true;
}

/* AccessTokenInterface */
public function getAccessToken($access_token)
{
$token = $this->getObjectByType('access_token_table',$access_token);

return is_null($token) ? false : $token;
}

public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{
// if it exists, update it.
if ($this->getAccessToken($access_token)) {
$this->setObjectByType('access_token_table',$access_token, array(
'access_token' => $access_token,
'client_id' => $client_id,
'expires' => $expires,
'user_id' => $user_id,
'scope' => $scope
));
} else {
$this->setObjectByType('access_token_table',$access_token, array(
'access_token' => $access_token,
'client_id' => $client_id,
'expires' => $expires,
'user_id' => $user_id,
'scope' => $scope
));
throw new \InvalidArgumentException('First argument to ' . __CLASS__ . ' must be an instance of Couchbase or a configuration array containing a servers array');
}

return true;
$this->config = array_merge($this->config, $config);
}

/* AuthorizationCodeInterface */
public function getAuthorizationCode($code)
protected function makeKey($table, $key)
{
$code = $this->getObjectByType('code_table',$code);

return is_null($code) ? false : $code;
return $table . '-' . $key;
}

public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function get($table, $key)
{
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
$this->setObjectByType('code_table',$code, array(
'authorization_code' => $code,
'client_id' => $client_id,
'user_id' => $user_id,
'redirect_uri' => $redirect_uri,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
));
} else {
$this->setObjectByType('code_table',$code,array(
'authorization_code' => $code,
'client_id' => $client_id,
'user_id' => $user_id,
'redirect_uri' => $redirect_uri,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
));
}

return true;
}

public function expireAuthorizationCode($code)
{
$this->deleteObjectByType('code_table',$code);

return true;
}

/* UserCredentialsInterface */
public function checkUserCredentials($username, $password)
{
if ($user = $this->getUser($username)) {
return $this->checkPassword($user, $password);
}

return false;
}

public function getUserDetails($username)
{
if ($user = $this->getUser($username)) {
$user['user_id'] = $user['username'];
}

return $user;
}

/* RefreshTokenInterface */
public function getRefreshToken($refresh_token)
{
$token = $this->getObjectByType('refresh_token_table',$refresh_token);

return is_null($token) ? false : $token;
}

public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{
$this->setObjectByType('refresh_token_table',$refresh_token, array(
'refresh_token' => $refresh_token,
'client_id' => $client_id,
'user_id' => $user_id,
'expires' => $expires,
'scope' => $scope
));

return true;
}

public function unsetRefreshToken($refresh_token)
{
$this->deleteObjectByType('refresh_token_table',$refresh_token);

return true;
}

// plaintext passwords are bad! Override this for your application
protected function checkPassword($user, $password)
{
return $user['password'] == $password;
}

public function getUser($username)
{
$result = $this->getObjectByType('user_table',$username);

return is_null($result) ? false : $result;
}

public function setUser($username, $password, $firstName = null, $lastName = null)
{
if ($this->getUser($username)) {
$this->setObjectByType('user_table',$username, array(
'username' => $username,
'password' => $password,
'first_name' => $firstName,
'last_name' => $lastName
));

} else {
$this->setObjectByType('user_table',$username, array(
'username' => $username,
'password' => $password,
'first_name' => $firstName,
'last_name' => $lastName
));

}

return true;
}

public function getClientKey($client_id, $subject)
{
if (!$jwt = $this->getObjectByType('jwt_table',$client_id)) {
return false;
}

if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
return $jwt['key'];
}

return false;
}

public function getClientScope($client_id)
{
if (!$clientDetails = $this->getClientDetails($client_id)) {
return false;
}

if (isset($clientDetails['scope'])) {
return $clientDetails['scope'];
}

return null;
return json_decode($this->db->get($this->makeKey($table, $key)), true);
}

public function getJti($client_id, $subject, $audience, $expiration, $jti)
public function set($table, $key, $value)
{
//TODO: Needs couchbase implementation.
throw new \Exception('getJti() for the Couchbase driver is currently unimplemented.');
return $this->db->set($this->makeKey($table, $key), json_encode($value));
}

public function setJti($client_id, $subject, $audience, $expiration, $jti)
public function delete($table, $key)
{
//TODO: Needs couchbase implementation.
throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.');
return $this->db->delete($this->makeKey($table, $key), '', 1);
}
}
Loading