summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/OAuth2/ClientAssertionType/HttpBasic.php19
-rw-r--r--src/OAuth2/Controller/AuthorizeController.php53
-rw-r--r--src/OAuth2/Controller/ResourceController.php4
-rw-r--r--src/OAuth2/GrantType/AuthorizationCode.php3
-rw-r--r--src/OAuth2/GrantType/JwtBearer.php9
-rw-r--r--src/OAuth2/GrantType/RefreshToken.php18
-rw-r--r--src/OAuth2/GrantType/UserCredentials.php3
-rw-r--r--src/OAuth2/OpenID/Controller/AuthorizeController.php19
-rw-r--r--src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php3
-rw-r--r--src/OAuth2/OpenID/Controller/UserInfoController.php3
-rw-r--r--src/OAuth2/OpenID/GrantType/AuthorizationCode.php3
-rw-r--r--src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php17
-rw-r--r--src/OAuth2/OpenID/ResponseType/IdToken.php1
-rw-r--r--src/OAuth2/OpenID/ResponseType/IdTokenInterface.php8
-rw-r--r--src/OAuth2/OpenID/ResponseType/TokenIdToken.php1
-rw-r--r--src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php21
-rw-r--r--src/OAuth2/Request.php1
-rw-r--r--src/OAuth2/Response.php6
-rw-r--r--src/OAuth2/ResponseInterface.php2
-rw-r--r--src/OAuth2/ResponseType/AccessToken.php39
-rw-r--r--src/OAuth2/ResponseType/AccessTokenInterface.php12
-rw-r--r--src/OAuth2/ResponseType/AuthorizationCode.php4
-rw-r--r--src/OAuth2/ResponseType/AuthorizationCodeInterface.php14
-rw-r--r--src/OAuth2/ResponseType/CryptoToken.php33
-rw-r--r--src/OAuth2/Scope.php4
-rw-r--r--src/OAuth2/Server.php26
-rw-r--r--src/OAuth2/Storage/AccessTokenInterface.php15
-rw-r--r--src/OAuth2/Storage/AuthorizationCodeInterface.php18
-rw-r--r--src/OAuth2/Storage/Cassandra.php9
-rw-r--r--src/OAuth2/Storage/ClientInterface.php24
-rw-r--r--src/OAuth2/Storage/CryptoToken.php27
-rw-r--r--src/OAuth2/Storage/DynamoDB.php518
-rw-r--r--src/OAuth2/Storage/Pdo.php86
-rw-r--r--src/OAuth2/Storage/ScopeInterface.php2
-rw-r--r--src/OAuth2/TokenType/Bearer.php4
35 files changed, 786 insertions, 243 deletions
diff --git a/src/OAuth2/ClientAssertionType/HttpBasic.php b/src/OAuth2/ClientAssertionType/HttpBasic.php
index 0e76154..0ecb7e1 100644
--- a/src/OAuth2/ClientAssertionType/HttpBasic.php
+++ b/src/OAuth2/ClientAssertionType/HttpBasic.php
@@ -19,16 +19,14 @@ class HttpBasic implements ClientAssertionTypeInterface
protected $config;
/**
- * @param OAuth2\Storage\ClientCredentialsInterface $clientStorage
- * REQUIRED Storage class for retrieving client credentials information
- * @param array $config
- * OPTIONAL Configuration options for the server
- * @code
- * $config = array(
- * 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
- * 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
- * );
- * @endcode
+ * @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information
+ * @param array $config OPTIONAL Configuration options for the server
+ * <code>
+ * $config = array(
+ * 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
+ * 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
+ * );
+ * </code>
*/
public function __construct(ClientCredentialsInterface $storage, array $config = array())
{
@@ -110,6 +108,7 @@ class HttpBasic implements ClientAssertionTypeInterface
* client_secret can be null if the client's password is an empty string
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
*/
+
return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
}
}
diff --git a/src/OAuth2/Controller/AuthorizeController.php b/src/OAuth2/Controller/AuthorizeController.php
index e669824..d57d38e 100644
--- a/src/OAuth2/Controller/AuthorizeController.php
+++ b/src/OAuth2/Controller/AuthorizeController.php
@@ -25,23 +25,19 @@ class AuthorizeController implements AuthorizeControllerInterface
protected $scopeUtil;
/**
- * @param OAuth2\Storage\ClientInterface $clientStorage
- * REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
- * @param array $responseTypes
- * OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
- * keys are "code" and "token"
- * @param array $config
- * OPTIONAL Configuration options for the server
- * @code
- * $config = array(
- * 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
- * 'enforce_state' => true // if the controller should require the "state" parameter
- * 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
- * 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
- * );
- * @endcode
- * @param OAuth2\ScopeInterface $scopeUtil
- * OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
+ * @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
+ * @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
+ * keys are "code" and "token"
+ * @param array $config OPTIONAL Configuration options for the server
+ * <code>
+ * $config = array(
+ * 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
+ * 'enforce_state' => true // if the controller should require the "state" parameter
+ * 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
+ * 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
+ * );
+ * </code>
+ * @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
*/
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
{
@@ -81,7 +77,7 @@ class AuthorizeController implements AuthorizeControllerInterface
// the user declined access to the client's application
if ($is_authorized === false) {
$redirect_uri = $this->redirect_uri ?: $registered_redirect_uri;
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, 'access_denied', "The user denied access to your application");
+ $this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id);
return;
}
@@ -105,6 +101,13 @@ class AuthorizeController implements AuthorizeControllerInterface
$response->setRedirect($this->config['redirect_status_code'], $uri);
}
+ protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
+ {
+ $error = 'access_denied';
+ $error_message = 'The user denied access to your application';
+ $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
+ }
+
/*
* We have made this protected so this class can be extended to add/modify
* these parameters
@@ -264,10 +267,8 @@ class AuthorizeController implements AuthorizeControllerInterface
/**
* Build the absolute URI based on supplied URI and parameters.
*
- * @param $uri
- * An absolute URI.
- * @param $params
- * Parameters to be append as GET.
+ * @param $uri An absolute URI.
+ * @param $params Parameters to be append as GET.
*
* @return
* An absolute URI with supplied parameters.
@@ -311,11 +312,9 @@ class AuthorizeController implements AuthorizeControllerInterface
/**
* Internal method for validating redirect URI supplied
*
- * @param string $inputUri
- * The submitted URI to be validated
- * @param string $registeredUriString
- * The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
- * allow for multiple URIs
+ * @param string $inputUri The submitted URI to be validated
+ * @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
+ * allow for multiple URIs
*
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
*/
diff --git a/src/OAuth2/Controller/ResourceController.php b/src/OAuth2/Controller/ResourceController.php
index 9623b9f..e858818 100644
--- a/src/OAuth2/Controller/ResourceController.php
+++ b/src/OAuth2/Controller/ResourceController.php
@@ -81,9 +81,9 @@ class ResourceController implements ResourceControllerInterface
if (!$token = $this->tokenStorage->getAccessToken($token_param)) {
$response->setError(401, 'invalid_token', 'The access token provided is invalid');
} elseif (!isset($token["expires"]) || !isset($token["client_id"])) {
- $response->setError(401, 'invalid_token', 'Malformed token (missing "expires")');
+ $response->setError(401, 'malformed_token', 'Malformed token (missing "expires")');
} elseif (time() > $token["expires"]) {
- $response->setError(401, 'invalid_token', 'The access token provided has expired');
+ $response->setError(401, 'expired_token', 'The access token provided has expired');
} else {
return $token;
}
diff --git a/src/OAuth2/GrantType/AuthorizationCode.php b/src/OAuth2/GrantType/AuthorizationCode.php
index 69f291e..e899520 100644
--- a/src/OAuth2/GrantType/AuthorizationCode.php
+++ b/src/OAuth2/GrantType/AuthorizationCode.php
@@ -17,8 +17,7 @@ class AuthorizationCode implements GrantTypeInterface
protected $authCode;
/**
- * @param OAuth2\Storage\AuthorizationCodeInterface $storage
- * REQUIRED Storage class for retrieving authorization code information
+ * @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information
*/
public function __construct(AuthorizationCodeInterface $storage)
{
diff --git a/src/OAuth2/GrantType/JwtBearer.php b/src/OAuth2/GrantType/JwtBearer.php
index 534feae..ebc5d5a 100644
--- a/src/OAuth2/GrantType/JwtBearer.php
+++ b/src/OAuth2/GrantType/JwtBearer.php
@@ -29,12 +29,9 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/**
* Creates an instance of the JWT bearer grant type.
*
- * @param OAuth2\Storage\JWTBearerInterface $storage
- * A valid storage interface that implements storage hooks for the JWT bearer grant type.
- * @param string $audience
- * The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
- * @param OAuth2\Encryption\JWT OPTIONAL $jwtUtil
- * The class used to decode, encode and verify JWTs.
+ * @param OAuth2\Storage\JWTBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
+ * @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
+ * @param OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
*/
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null)
{
diff --git a/src/OAuth2/GrantType/RefreshToken.php b/src/OAuth2/GrantType/RefreshToken.php
index 71b1bdb..d6691df 100644
--- a/src/OAuth2/GrantType/RefreshToken.php
+++ b/src/OAuth2/GrantType/RefreshToken.php
@@ -19,15 +19,13 @@ class RefreshToken implements GrantTypeInterface
protected $config;
/**
- * @param OAuth2\Storage\RefreshTokenInterface $storage
- * REQUIRED Storage class for retrieving refresh token information
- * @param array $config
- * OPTIONAL Configuration options for the server
- * @code
- * $config = array(
- * 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
- * );
- * @endcode
+ * @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information
+ * @param array $config OPTIONAL Configuration options for the server
+ * <code>
+ * $config = array(
+ * 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
+ * );
+ * </code>
*/
public function __construct(RefreshTokenInterface $storage, $config = array())
{
@@ -80,7 +78,7 @@ class RefreshToken implements GrantTypeInterface
public function getScope()
{
- return $this->refreshToken['scope'];
+ return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
}
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
diff --git a/src/OAuth2/GrantType/UserCredentials.php b/src/OAuth2/GrantType/UserCredentials.php
index 5d72aaf..f165538 100644
--- a/src/OAuth2/GrantType/UserCredentials.php
+++ b/src/OAuth2/GrantType/UserCredentials.php
@@ -18,8 +18,7 @@ class UserCredentials implements GrantTypeInterface
protected $storage;
/**
- * @param OAuth2\Storage\UserCredentialsInterface $storage
- * REQUIRED Storage class for retrieving user credentials information
+ * @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information
*/
public function __construct(UserCredentialsInterface $storage)
{
diff --git a/src/OAuth2/OpenID/Controller/AuthorizeController.php b/src/OAuth2/OpenID/Controller/AuthorizeController.php
index 4850ebe..c6fe4f9 100644
--- a/src/OAuth2/OpenID/Controller/AuthorizeController.php
+++ b/src/OAuth2/OpenID/Controller/AuthorizeController.php
@@ -13,6 +13,25 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
{
private $nonce;
+ protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
+ {
+ $prompt = $request->query('prompt', 'consent');
+ if ($prompt == 'none') {
+ if (is_null($user_id)) {
+ $error = 'login_required';
+ $error_message = 'The user must log in';
+ } else {
+ $error = 'interaction_required';
+ $error_message = 'The user must grant access to your application';
+ }
+ } else {
+ $error = 'consent_required';
+ $error_message = 'The user denied access to your application';
+ }
+
+ $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message);
+ }
+
protected function buildAuthorizeParameters($request, $response, $user_id)
{
if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) {
diff --git a/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php b/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
index af47cd0..62704e7 100644
--- a/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
+++ b/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
@@ -2,9 +2,6 @@
namespace OAuth2\OpenID\Controller;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
interface AuthorizeControllerInterface
{
const RESPONSE_TYPE_ID_TOKEN = 'id_token';
diff --git a/src/OAuth2/OpenID/Controller/UserInfoController.php b/src/OAuth2/OpenID/Controller/UserInfoController.php
index 28e429e..30cb942 100644
--- a/src/OAuth2/OpenID/Controller/UserInfoController.php
+++ b/src/OAuth2/OpenID/Controller/UserInfoController.php
@@ -2,6 +2,7 @@
namespace OAuth2\OpenID\Controller;
+use OAuth2\Scope;
use OAuth2\TokenType\TokenTypeInterface;
use OAuth2\Storage\AccessTokenInterface;
use OAuth2\OpenID\Storage\UserClaimsInterface;
@@ -52,6 +53,6 @@ class UserInfoController extends ResourceController implements UserInfoControlle
$claims += array(
'sub' => $token['user_id'],
);
- $response->setParameters($claims);
+ $response->addParameters($claims);
}
}
diff --git a/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
index 4a5da01..8ed1edc 100644
--- a/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
+++ b/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
@@ -3,10 +3,7 @@
namespace OAuth2\OpenID\GrantType;
use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
-use OAuth2\Storage\AuthorizationCodeInterface;
use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
/**
*
diff --git a/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php b/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
index 7b8de7c..ea47792 100644
--- a/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
+++ b/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
@@ -13,17 +13,12 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
/**
* Handle the creation of the authorization code.
*
- * @param $client_id
- * Client identifier related to the authorization code
- * @param $user_id
- * User ID associated with the authorization code
- * @param $redirect_uri
- * An absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param $id_token
- * (optional) The OpenID Connect id_token.
+ * @param $client_id Client identifier related to the authorization code
+ * @param $user_id User ID associated with the authorization code
+ * @param $redirect_uri An absolute URI to which the authorization server will redirect the
+ * user-agent to when the end-user authorization step is completed.
+ * @param $scope OPTIONAL Scopes to be stored in space-separated string.
+ * @param $id_token OPTIONAL The OpenID Connect id_token.
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
diff --git a/src/OAuth2/OpenID/ResponseType/IdToken.php b/src/OAuth2/OpenID/ResponseType/IdToken.php
index 8d907bc..4696155 100644
--- a/src/OAuth2/OpenID/ResponseType/IdToken.php
+++ b/src/OAuth2/OpenID/ResponseType/IdToken.php
@@ -4,7 +4,6 @@ namespace OAuth2\OpenID\ResponseType;
use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt;
-use OAuth2\Storage\RefreshTokenInterface;
use OAuth2\Storage\PublicKeyInterface;
use OAuth2\OpenID\Storage\UserClaimsInterface;
diff --git a/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php b/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
index 3dfb57e..0bd2f83 100644
--- a/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
+++ b/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
@@ -15,10 +15,10 @@ interface IdTokenInterface extends ResponseTypeInterface
* If the Implicit Flow is used, the token and id_token are generated and
* returned together.
*
- * @param string $client_id The client id.
- * @param string $user_id The user id.
- * @param string $nonce OPTIONAL The nonce.
- * @param string $userClaims OPTIONAL Claims about the user.
+ * @param string $client_id The client id.
+ * @param string $user_id The user id.
+ * @param string $nonce OPTIONAL The nonce.
+ * @param string $userClaims OPTIONAL Claims about the user.
* @param string $access_token OPTIONAL The access token, if known.
*
* @return string The ID Token represented as a JSON Web Token (JWT).
diff --git a/src/OAuth2/OpenID/ResponseType/TokenIdToken.php b/src/OAuth2/OpenID/ResponseType/TokenIdToken.php
index 67f2a4a..5567569 100644
--- a/src/OAuth2/OpenID/ResponseType/TokenIdToken.php
+++ b/src/OAuth2/OpenID/ResponseType/TokenIdToken.php
@@ -3,7 +3,6 @@
namespace OAuth2\OpenID\ResponseType;
use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\ResponseType\ResponseTypeInterface;
class TokenIdToken implements TokenIdTokenInterface
{
diff --git a/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php b/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
index 3c6d00b..51dd867 100644
--- a/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
+++ b/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
@@ -23,20 +23,13 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
*
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
*
- * @param $code
- * Authorization code to be stored.
- * @param $client_id
- * Client identifier to be stored.
- * @param $user_id
- * User identifier to be stored.
- * @param string $redirect_uri
- * Redirect URI(s) to be stored in a space-separated string.
- * @param int $expires
- * Expiration to be stored as a Unix timestamp.
- * @param string $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param string $id_token
- * (optional) The OpenID Connect id_token.
+ * @param $code authorization code to be stored.
+ * @param $client_id client identifier to be stored.
+ * @param $user_id user identifier to be stored.
+ * @param string $redirect_uri redirect URI(s) to be stored in a space-separated string.
+ * @param int $expires expiration to be stored as a Unix timestamp.
+ * @param string $scope OPTIONAL scopes to be stored in space-separated string.
+ * @param string $id_token OPTIONAL the OpenID Connect id_token.
*
* @ingroup oauth2_section_4
*/
diff --git a/src/OAuth2/Request.php b/src/OAuth2/Request.php
index b37c591..faec0ce 100644
--- a/src/OAuth2/Request.php
+++ b/src/OAuth2/Request.php
@@ -82,6 +82,7 @@ class Request implements RequestInterface
{
$headers = array_change_key_case($this->headers);
$name = strtolower($name);
+
return isset($headers[$name]) ? $headers[$name] : $default;
}
diff --git a/src/OAuth2/Response.php b/src/OAuth2/Response.php
index d746789..d8eabe7 100644
--- a/src/OAuth2/Response.php
+++ b/src/OAuth2/Response.php
@@ -181,13 +181,13 @@ class Response implements ResponseInterface
// this only works for single-level arrays
$xml = new \SimpleXMLElement('<response/>');
foreach ($this->parameters as $key => $param) {
- $xml->addChild($param, $key);
+ $xml->addChild($key, $param);
}
return $xml->asXML();
}
- throw new \InvalidArgumentException(sprintf('The format %s is not supported'));
+ throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
}
@@ -243,7 +243,7 @@ class Response implements ResponseInterface
}
}
- public function setRedirect($statusCode = 302, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
+ public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
{
if (empty($url)) {
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
diff --git a/src/OAuth2/ResponseInterface.php b/src/OAuth2/ResponseInterface.php
index 842002b..c99b5f7 100644
--- a/src/OAuth2/ResponseInterface.php
+++ b/src/OAuth2/ResponseInterface.php
@@ -18,7 +18,7 @@ interface ResponseInterface
public function setError($statusCode, $name, $description = null, $uri = null);
- public function setRedirect($statusCode = 302, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
+ public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
public function getParameter($name);
}
diff --git a/src/OAuth2/ResponseType/AccessToken.php b/src/OAuth2/ResponseType/AccessToken.php
index 0fb1121..b05bf87 100644
--- a/src/OAuth2/ResponseType/AccessToken.php
+++ b/src/OAuth2/ResponseType/AccessToken.php
@@ -16,19 +16,16 @@ class AccessToken implements AccessTokenInterface
protected $config;
/**
- * @param OAuth2\Storage\AccessTokenInterface $tokenStorage
- * REQUIRED Storage class for saving access token information
- * @param OAuth2\Storage\RefreshTokenInterface $refreshStorage
- * OPTIONAL Storage class for saving refresh token information
- * @param array $config
- * OPTIONAL Configuration options for the server
- * @code
- * $config = array(
- * 'token_type' => 'bearer', // token type identifier
- * 'access_lifetime' => 3600, // time before access token expires
- * 'refresh_token_lifetime' => 1209600, // time before refresh token expires
- * );
- * @endcode
+ * @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information
+ * @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information
+ * @param array $config OPTIONAL Configuration options for the server
+ * <code>
+ * $config = array(
+ * 'token_type' => 'bearer', // token type identifier
+ * 'access_lifetime' => 3600, // time before access token expires
+ * 'refresh_token_lifetime' => 1209600, // time before refresh token expires
+ * );
+ * </endcode>
*/
public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
{
@@ -67,14 +64,10 @@ class AccessToken implements AccessTokenInterface
/**
* Handle the creation of access token, also issue refresh token if supported / desirable.
*
- * @param $client_id
- * Client identifier related to the access token.
- * @param $user_id
- * User ID associated with the access token
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param bool $includeRefreshToken
- * If true, a new refresh_token will be added to the response
+ * @param $client_id client identifier related to the access token.
+ * @param $user_id user ID associated with the access token
+ * @param $scope OPTIONAL scopes to be stored in space-separated string.
+ * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5
@@ -124,9 +117,9 @@ class AccessToken implements AccessTokenInterface
$tokenLen = 40;
if (function_exists('mcrypt_create_iv')) {
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);
- } else if (function_exists('openssl_random_pseudo_bytes')) {
+ } elseif (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(100);
- } else if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
+ } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
$randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
} else {
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
diff --git a/src/OAuth2/ResponseType/AccessTokenInterface.php b/src/OAuth2/ResponseType/AccessTokenInterface.php
index 9190327..2ba4a4f 100644
--- a/src/OAuth2/ResponseType/AccessTokenInterface.php
+++ b/src/OAuth2/ResponseType/AccessTokenInterface.php
@@ -11,14 +11,10 @@ interface AccessTokenInterface extends ResponseTypeInterface
/**
* Handle the creation of access token, also issue refresh token if supported / desirable.
*
- * @param $client_id
- * Client identifier related to the access token.
- * @param $user_id
- * User ID associated with the access token
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param bool $includeRefreshToken
- * If true, a new refresh_token will be added to the response
+ * @param $client_id client identifier related to the access token.
+ * @param $user_id user ID associated with the access token
+ * @param $scope OPTONAL scopes to be stored in space-separated string.
+ * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5
diff --git a/src/OAuth2/ResponseType/AuthorizationCode.php b/src/OAuth2/ResponseType/AuthorizationCode.php
index 51bd437..6a305fd 100644
--- a/src/OAuth2/ResponseType/AuthorizationCode.php
+++ b/src/OAuth2/ResponseType/AuthorizationCode.php
@@ -87,9 +87,9 @@ class AuthorizationCode implements AuthorizationCodeInterface
$tokenLen = 40;
if (function_exists('mcrypt_create_iv')) {
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);
- } else if (function_exists('openssl_random_pseudo_bytes')) {
+ } elseif (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(100);
- } else if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
+ } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
$randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
} else {
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
diff --git a/src/OAuth2/ResponseType/AuthorizationCodeInterface.php b/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
index 9d5b90f..df777e2 100644
--- a/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
+++ b/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
@@ -17,15 +17,11 @@ interface AuthorizationCodeInterface extends ResponseTypeInterface
/**
* Handle the creation of the authorization code.
*
- * @param $client_id
- * Client identifier related to the authorization code
- * @param $user_id
- * User ID associated with the authorization code
- * @param $redirect_uri
- * An absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
+ * @param $client_id client identifier related to the authorization code
+ * @param $user_id user id associated with the authorization code
+ * @param $redirect_uri an absolute URI to which the authorization server will redirect the
+ * user-agent to when the end-user authorization step is completed.
+ * @param $scope OPTIONAL scopes to be stored in space-separated string.
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
diff --git a/src/OAuth2/ResponseType/CryptoToken.php b/src/OAuth2/ResponseType/CryptoToken.php
index 3f5ca37..08ff853 100644
--- a/src/OAuth2/ResponseType/CryptoToken.php
+++ b/src/OAuth2/ResponseType/CryptoToken.php
@@ -51,7 +51,7 @@ class CryptoToken extends AccessToken
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param bool $includeRefreshToken
- * If true, a new refresh_token will be added to the response
+ * If true, a new refresh_token will be added to the response
*
* @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5
@@ -70,21 +70,6 @@ class CryptoToken extends AccessToken
);
/*
- * Issue a refresh token also, if we support them
- *
- * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
- * is supplied in the constructor
- */
- if ($includeRefreshToken && $this->refreshStorage) {
- $cryptoToken["refresh_token"] = $this->generateRefreshToken();
- $expires = 0;
- if ($this->config['refresh_token_lifetime'] > 0) {
- $expires = time() + $this->config['refresh_token_lifetime'];
- }
- $this->refreshStorage->setRefreshToken($cryptoToken['refresh_token'], $client_id, $user_id, $expires, $scope);
- }
-
- /*
* Encode the token data into a single access_token string
*/
$access_token = $this->encodeToken($cryptoToken, $client_id);
@@ -105,6 +90,22 @@ class CryptoToken extends AccessToken
'scope' => $scope
);
+ /*
+ * Issue a refresh token also, if we support them
+ *
+ * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
+ * is supplied in the constructor
+ */
+ if ($includeRefreshToken && $this->refreshStorage) {
+ $refresh_token = $this->generateRefreshToken();
+ $expires = 0;
+ if ($this->config['refresh_token_lifetime'] > 0) {
+ $expires = time() + $this->config['refresh_token_lifetime'];
+ }
+ $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
+ $token['refresh_token'] = $refresh_token;
+ }
+
return $token;
}
diff --git a/src/OAuth2/Scope.php b/src/OAuth2/Scope.php
index 5c792bb..c44350b 100644
--- a/src/OAuth2/Scope.php
+++ b/src/OAuth2/Scope.php
@@ -68,10 +68,10 @@ class Scope implements ScopeInterface
$nonReservedScopes = array_diff($scope, $reservedScope);
if (count($nonReservedScopes) == 0) {
return true;
- }
- else {
+ } else {
// Check the storage for non-reserved scopes.
$nonReservedScopes = implode(' ', $nonReservedScopes);
+
return $this->storage->scopeExists($nonReservedScopes);
}
}
diff --git a/src/OAuth2/Server.php b/src/OAuth2/Server.php
index b138a55..3434a7b 100644
--- a/src/OAuth2/Server.php
+++ b/src/OAuth2/Server.php
@@ -83,22 +83,15 @@ class Server implements ResourceControllerInterface,
);
/**
- * @param mixed $storage
- * array - array of Objects to implement storage
- * OAuth2\Storage object implementing all required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
- * @param array $config
- * specify a different token lifetime, token header name, etc
- * @param array $grantTypes
- * An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
- * @param array $responseTypes
- * Response types to use. array keys should be "code" and and "token" for
- * Access Token and Authorization Code response types
- * @param OAuth2\TokenType\TokenTypeInterface $tokenType
- * The token type object to use. Valid token types are "bearer" and "mac"
- * @param OAuth2\ScopeInterface $scopeUtil
- * The scope utility class to use to validate scope
- * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType
- * The method in which to verify the client identity. Default is HttpBasic
+ * @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the
+ * required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
+ * @param array $config specify a different token lifetime, token header name, etc
+ * @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
+ * @param array $responseTypes Response types to use. array keys should be "code" and and "token" for
+ * Access Token and Authorization Code response types
+ * @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
+ * @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope
+ * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
*
* @ingroup oauth2_section_7
*/
@@ -719,6 +712,7 @@ class Server implements ResourceControllerInterface,
}
$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
+
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
}
diff --git a/src/OAuth2/Storage/AccessTokenInterface.php b/src/OAuth2/Storage/AccessTokenInterface.php
index b55c3d6..d382f89 100644
--- a/src/OAuth2/Storage/AccessTokenInterface.php
+++ b/src/OAuth2/Storage/AccessTokenInterface.php
@@ -36,16 +36,11 @@ interface AccessTokenInterface
*
* We need to store access token data as we create and verify tokens.
*
- * @param $oauth_token
- * oauth_token to be stored.
- * @param $client_id
- * Client identifier to be stored.
- * @param $user_id
- * User identifier to be stored.
- * @param int $expires
- * Expiration to be stored as a Unix timestamp.
- * @param string $scope
- * (optional) Scopes to be stored in space-separated string.
+ * @param $oauth_token oauth_token to be stored.
+ * @param $client_id client identifier to be stored.
+ * @param $user_id user identifier to be stored.
+ * @param int $expires expiration to be stored as a Unix timestamp.
+ * @param string $scope OPTIONAL Scopes to be stored in space-separated string.
*
* @ingroup oauth2_section_4
*/
diff --git a/src/OAuth2/Storage/AuthorizationCodeInterface.php b/src/OAuth2/Storage/AuthorizationCodeInterface.php
index d59a61f..3beb0e4 100644
--- a/src/OAuth2/Storage/AuthorizationCodeInterface.php
+++ b/src/OAuth2/Storage/AuthorizationCodeInterface.php
@@ -59,18 +59,12 @@ interface AuthorizationCodeInterface
*
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
*
- * @param $code
- * Authorization code to be stored.
- * @param $client_id
- * Client identifier to be stored.
- * @param $user_id
- * User identifier to be stored.
- * @param string $redirect_uri
- * Redirect URI(s) to be stored in a space-separated string.
- * @param int $expires
- * Expiration to be stored as a Unix timestamp.
- * @param string $scope
- * (optional) Scopes to be stored in space-separated string.
+ * @param string $code Authorization code to be stored.
+ * @param mixed $client_id Client identifier to be stored.
+ * @param mixed $user_id User identifier to be stored.
+ * @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string.
+ * @param int $expires Expiration to be stored as a Unix timestamp.
+ * @param string $scope OPTIONAL Scopes to be stored in space-separated string.
*
* @ingroup oauth2_section_4
*/
diff --git a/src/OAuth2/Storage/Cassandra.php b/src/OAuth2/Storage/Cassandra.php
index f6d1e05..9587b4c 100644
--- a/src/OAuth2/Storage/Cassandra.php
+++ b/src/OAuth2/Storage/Cassandra.php
@@ -50,7 +50,7 @@ class Cassandra implements AuthorizationCodeInterface,
* Cassandra Storage! uses phpCassa
*
* @param \phpcassa\ConnectionPool $cassandra
- * @param array $config
+ * @param array $config
*/
public function __construct($connection = array(), array $config = array())
{
@@ -112,14 +112,14 @@ class Cassandra implements AuthorizationCodeInterface,
$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) {
+ } catch (\Exception $e) {
return false;
}
} else {
try {
// __data key set as C* requires a field
$cf->insert($key, array('__data' => $str));
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
return false;
}
}
@@ -135,7 +135,7 @@ class Cassandra implements AuthorizationCodeInterface,
try {
// __data key set as C* requires a field
$cf->remove($key, array('__data'));
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
return false;
}
@@ -364,4 +364,3 @@ class Cassandra implements AuthorizationCodeInterface,
throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
}
}
-
diff --git a/src/OAuth2/Storage/ClientInterface.php b/src/OAuth2/Storage/ClientInterface.php
index ec8d7fd..09a5bff 100644
--- a/src/OAuth2/Storage/ClientInterface.php
+++ b/src/OAuth2/Storage/ClientInterface.php
@@ -20,18 +20,18 @@ interface ClientInterface
* Client identifier to be check with.
*
* @return array
- * Client details. The only mandatory key in the array is "redirect_uri".
- * This function MUST return FALSE if the given client does not exist or is
- * invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris.
- * @code
- * return array(
- * "redirect_uri" => REDIRECT_URI, // REQUIRED redirect_uri registered for the client
- * "client_id" => CLIENT_ID, // OPTIONAL the client id
- * "grant_types" => GRANT_TYPES, // OPTIONAL an array of restricted grant types
- * "user_id" => USER_ID, // OPTIONAL the user identifier associated with this client
- * "scope" => SCOPE, // OPTIONAL the scopes allowed for this client
- * );
- * @endcode
+ * Client details. The only mandatory key in the array is "redirect_uri".
+ * This function MUST return FALSE if the given client does not exist or is
+ * invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris.
+ * <code>
+ * return array(
+ * "redirect_uri" => REDIRECT_URI, // REQUIRED redirect_uri registered for the client
+ * "client_id" => CLIENT_ID, // OPTIONAL the client id
+ * "grant_types" => GRANT_TYPES, // OPTIONAL an array of restricted grant types
+ * "user_id" => USER_ID, // OPTIONAL the user identifier associated with this client
+ * "scope" => SCOPE, // OPTIONAL the scopes allowed for this client
+ * );
+ * </code>
*
* @ingroup oauth2_section_4
*/
diff --git a/src/OAuth2/Storage/CryptoToken.php b/src/OAuth2/Storage/CryptoToken.php
index f107e45..31ebb65 100644
--- a/src/OAuth2/Storage/CryptoToken.php
+++ b/src/OAuth2/Storage/CryptoToken.php
@@ -16,28 +16,11 @@ class CryptoToken implements CryptoTokenInterface
protected $encryptionUtil;
/**
- * @param string $publicKey
- * the public key encryption to use
- *
- * @param string $privateKey (optional)
- * (optional) the private key to use to sign tokens
- * this is only required for token granting, and can be omitted for resource servers,
- * as only the publc key is required for crypto token verification
- *
- * @param array $config
- * (optional) configuration array. Valid parameters are
- * - encryption_algorithm
- * the algorithm to use for encryption. This is passed to the
- * EncryptionInterface object.
- * @see OAuth2\Encryption\Jwt::verifySignature
- *
- * @param OAuth2\Storage\AccessTokenInterface $tokenStorage
- * (optional) persist the access token to another storage. This is useful if
- * you want to retain access token grant information somewhere, but
- * is not necessary when using this grant type.
- *
- * @param OAuth2\Encryption\EncryptionInterface $encryptionUtil
- * (optional) class to use for "encode" and "decode" functions.
+ * @param OAuth2\Encryption\PublicKeyInterface $publicKeyStorage the public key encryption to use
+ * @param OAuth2\Storage\AccessTokenInterface $tokenStorage OPTIONAL persist the access token to another storage. This is useful if
+ * you want to retain access token grant information somewhere, but
+ * is not necessary when using this grant type.
+ * @param OAuth2\Encryption\EncryptionInterface $encryptionUtil OPTIONAL class to use for "encode" and "decode" functions.
*/
public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null)
{
diff --git a/src/OAuth2/Storage/DynamoDB.php b/src/OAuth2/Storage/DynamoDB.php
new file mode 100644
index 0000000..fe06428
--- /dev/null
+++ b/src/OAuth2/Storage/DynamoDB.php
@@ -0,0 +1,518 @@
+<?php
+
+namespace OAuth2\Storage;
+
+use Aws\DynamoDb\DynamoDbClient;
+
+use OAuth2\OpenID\Storage\UserClaimsInterface;
+use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
+/**
+ * DynamoDB storage for all storage types
+ *
+ * To use, install "aws/aws-sdk-php" via composer
+ * <code>
+ * composer require aws/aws-sdk-php:dev-master
+ * </code>
+ *
+ * Once this is done, instantiate the DynamoDB client
+ * <code>
+ * $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION"));
+ * </code>
+ *
+ * Table :
+ * - oauth_access_tokens (primary hash key : access_token)
+ * - oauth_authorization_codes (primary hash key : authorization_code)
+ * - oauth_clients (primary hash key : client_id)
+ * - oauth_jwt (primary hash key : client_id, primary range key : subject)
+ * - oauth_public_keys (primary hash key : client_id)
+ * - oauth_refresh_tokens (primary hash key : refresh_token)
+ * - oauth_scopes (primary hash key : scope, secondary index : is_default-index hash key is_default)
+ * - oauth_users (primary hash key : username)
+ *
+ * @author Frederic AUGUSTE <frederic.auguste at gmail dot com>
+ */
+class DynamoDB implements
+ AuthorizationCodeInterface,
+ AccessTokenInterface,
+ ClientCredentialsInterface,
+ UserCredentialsInterface,
+ RefreshTokenInterface,
+ JwtBearerInterface,
+ ScopeInterface,
+ PublicKeyInterface,
+ UserClaimsInterface,
+ OpenIDAuthorizationCodeInterface
+{
+ protected $client;
+ protected $config;
+
+ public function __construct($connection, $config = array())
+ {
+ if (!($connection instanceof DynamoDbClient)) {
+ if (!is_array($connection)) {
+ throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region');
+ }
+ if (!array_key_exists("key",$connection) || !array_key_exists("secret",$connection) || !array_key_exists("region",$connection) ) {
+ throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region');
+ }
+ $this->client = DynamoDbClient::factory(array(
+ 'key' => $connection["key"],
+ 'secret' => $connection["secret"],
+ 'region' =>$connection["region"]
+ ));
+ } else {
+ $this->client = $connection;
+ }
+
+ $this->config = array_merge(array(
+ 'client_table' => 'oauth_clients',
+ 'access_token_table' => 'oauth_access_tokens',
+ 'refresh_token_table' => 'oauth_refresh_tokens',
+ 'code_table' => 'oauth_authorization_codes',
+ 'user_table' => 'oauth_users',
+ 'jwt_table' => 'oauth_jwt',
+ 'scope_table' => 'oauth_scopes',
+ 'public_key_table' => 'oauth_public_keys',
+ ), $config);
+ }
+
+ /* OAuth2\Storage\ClientCredentialsInterface */
+ public function checkClientCredentials($client_id, $client_secret = null)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['client_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+
+ return $result->count()==1 && $result["Item"]["client_secret"]["S"] == $client_secret;
+ }
+
+ public function isPublicClient($client_id)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['client_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+
+ if ($result->count()==0) {
+ return false ;
+ }
+
+ return empty($result["Item"]["client_secret"]);
+ }
+
+ /* OAuth2\Storage\ClientInterface */
+ public function getClientDetails($client_id)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['client_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $result = $this->dynamo2array($result);
+ foreach (array('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') as $key => $val) {
+ if (!array_key_exists ($val, $result)) {
+ $result[$val] = null;
+ }
+ }
+
+ return $result;
+ }
+
+ public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
+ {
+ $clientData = compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id');
+ $clientData = array_filter($clientData, function ($value) { return !is_null($value); });
+
+ $result = $this->client->putItem(array(
+ 'TableName' => $this->config['client_table'],
+ 'Item' => $this->client->formatAttributes($clientData)
+ ));
+
+ return true;
+ }
+
+ public function checkRestrictedGrantType($client_id, $grant_type)
+ {
+ $details = $this->getClientDetails($client_id);
+ if (isset($details['grant_types'])) {
+ $grant_types = explode(' ', $details['grant_types']);
+
+ return in_array($grant_type, (array) $grant_types);
+ }
+
+ // if grant_types are not defined, then none are restricted
+ return true;
+ }
+
+ /* OAuth2\Storage\AccessTokenInterface */
+ public function getAccessToken($access_token)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['access_token_table'],
+ "Key" => array('access_token' => array('S' => $access_token))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+ if (array_key_exists ('expires', $token)) {
+ $token['expires'] = strtotime($token['expires']);
+ }
+
+ return $token;
+ }
+
+ public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
+ {
+ // convert expires to datestring
+ $expires = date('Y-m-d H:i:s', $expires);
+
+ $clientData = compact('access_token', 'client_id', 'user_id', 'expires', 'scope');
+ $clientData = array_filter($clientData, function ($value) { return !is_null($value); });
+
+ $result = $this->client->putItem(array(
+ 'TableName' => $this->config['access_token_table'],
+ 'Item' => $this->client->formatAttributes($clientData)
+ ));
+
+ return true;
+
+ }
+
+ /* OAuth2\Storage\AuthorizationCodeInterface */
+ public function getAuthorizationCode($code)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['code_table'],
+ "Key" => array('authorization_code' => array('S' => $code))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+ if (!array_key_exists("id_token", $token )) {
+ $token['id_token'] = null;
+ }
+ $token['expires'] = strtotime($token['expires']);
+
+ return $token;
+
+ }
+
+ public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
+ {
+ // convert expires to datestring
+ $expires = date('Y-m-d H:i:s', $expires);
+
+ $clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'id_token', 'scope');
+ $clientData = array_filter($clientData, function ($value) { return !is_null($value); });
+
+ $result = $this->client->putItem(array(
+ 'TableName' => $this->config['code_table'],
+ 'Item' => $this->client->formatAttributes($clientData)
+ ));
+
+ return true;
+ }
+
+ public function expireAuthorizationCode($code)
+ {
+
+ $result = $this->client->deleteItem(array(
+ 'TableName' => $this->config['code_table'],
+ 'Key' => $this->client->formatAttributes(array("authorization_code" => $code))
+ ));
+
+ return true;
+ }
+
+ /* OAuth2\Storage\UserCredentialsInterface */
+ public function checkUserCredentials($username, $password)
+ {
+ if ($user = $this->getUser($username)) {
+ return $this->checkPassword($user, $password);
+ }
+
+ return false;
+ }
+
+ public function getUserDetails($username)
+ {
+ return $this->getUser($username);
+ }
+
+ /* UserClaimsInterface */
+ public function getUserClaims($user_id, $claims)
+ {
+ if (!$userDetails = $this->getUserDetails($user_id)) {
+ return false;
+ }
+
+ $claims = explode(' ', trim($claims));
+ $userClaims = array();
+
+ // for each requested claim, if the user has the claim, set it in the response
+ $validClaims = explode(' ', self::VALID_CLAIMS);
+ foreach ($validClaims as $validClaim) {
+ if (in_array($validClaim, $claims)) {
+ if ($validClaim == 'address') {
+ // address is an object with subfields
+ $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
+ } else {
+ $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
+ }
+ }
+ }
+
+ return $userClaims;
+ }
+
+ protected function getUserClaim($claim, $userDetails)
+ {
+ $userClaims = array();
+ $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
+ $claimValues = explode(' ', $claimValuesString);
+
+ foreach ($claimValues as $value) {
+ if ($value == 'email_verified') {
+ $userClaims[$value] = $userDetails[$value]=='true' ? true : false;
+ } else {
+ $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
+ }
+ }
+
+ return $userClaims;
+ }
+
+ /* OAuth2\Storage\RefreshTokenInterface */
+ public function getRefreshToken($refresh_token)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['refresh_token_table'],
+ "Key" => array('refresh_token' => array('S' => $refresh_token))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+ $token['expires'] = strtotime($token['expires']);
+
+ return $token;
+ }
+
+ public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
+ {
+ // convert expires to datestring
+ $expires = date('Y-m-d H:i:s', $expires);
+
+ $clientData = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope');
+ $clientData = array_filter($clientData, function ($value) { return !is_null($value); });
+
+ $result = $this->client->putItem(array(
+ 'TableName' => $this->config['refresh_token_table'],
+ 'Item' => $this->client->formatAttributes($clientData)
+ ));
+
+ return true;
+ }
+
+ public function unsetRefreshToken($refresh_token)
+ {
+ $result = $this->client->deleteItem(array(
+ 'TableName' => $this->config['refresh_token_table'],
+ 'Key' => $this->client->formatAttributes(array("refresh_token" => $refresh_token))
+ ));
+
+ return true;
+ }
+
+ // plaintext passwords are bad! Override this for your application
+ protected function checkPassword($user, $password)
+ {
+ return $user['password'] == sha1($password);
+ }
+
+ public function getUser($username)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['user_table'],
+ "Key" => array('username' => array('S' => $username))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+ $token['user_id'] = $username;
+
+ return $token;
+ }
+
+ public function setUser($username, $password, $first_name = null, $last_name = null)
+ {
+ // do not store in plaintext
+ $password = sha1($password);
+
+ $clientData = compact('username', 'password', 'first_name', 'last_name');
+ $clientData = array_filter($clientData, function ($value) { return !is_null($value); });
+
+ $result = $this->client->putItem(array(
+ 'TableName' => $this->config['user_table'],
+ 'Item' => $this->client->formatAttributes($clientData)
+ ));
+
+ return true;
+
+ }
+
+ /* ScopeInterface */
+ public function scopeExists($scope)
+ {
+ $scope = explode(' ', $scope);
+ $scope_query = array();
+ $count = 0;
+ foreach ($scope as $key => $val) {
+ $result = $this->client->query(array(
+ 'TableName' => $this->config['scope_table'],
+ 'Select' => 'COUNT',
+ 'KeyConditions' => array(
+ 'scope' => array(
+ 'AttributeValueList' => array(array('S' => $val)),
+ 'ComparisonOperator' => 'EQ'
+ )
+ )
+ ));
+ $count += $result['Count'];
+ }
+
+ return $count == count($scope);
+ }
+
+ public function getDefaultScope($client_id = null)
+ {
+
+ $result = $this->client->query(array(
+ 'TableName' => $this->config['scope_table'],
+ 'IndexName' => 'is_default-index',
+ 'Select' => 'ALL_ATTRIBUTES',
+ 'KeyConditions' => array(
+ 'is_default' => array(
+ 'AttributeValueList' => array(array('S' => 'true')),
+ 'ComparisonOperator' => 'EQ',
+ ),
+ )
+ ));
+ $defaultScope = array();
+ if ($result->count() > 0) {
+ $array = $result->toArray();
+ foreach ($array["Items"] as $item) {
+ $defaultScope[] = $item['scope']['S'];
+ }
+
+ return implode(' ', $defaultScope);
+ }
+
+ return null;
+ }
+
+ /* JWTBearerInterface */
+ public function getClientKey($client_id, $subject)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['jwt_table'],
+ "Key" => array('client_id' => array('S' => $client_id), 'subject' => array('S' => $subject))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+
+ return $token['public_key'];
+ }
+
+ public function getClientScope($client_id)
+ {
+ if (!$clientDetails = $this->getClientDetails($client_id)) {
+ return false;
+ }
+
+ if (isset($clientDetails['scope'])) {
+ return $clientDetails['scope'];
+ }
+
+ return null;
+ }
+
+ public function getJti($client_id, $subject, $audience, $expires, $jti)
+ {
+ //TODO not use.
+ }
+
+ public function setJti($client_id, $subject, $audience, $expires, $jti)
+ {
+ //TODO not use.
+ }
+
+ /* PublicKeyInterface */
+ public function getPublicKey($client_id = '0')
+ {
+
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['public_key_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+
+ return $token['public_key'];
+
+ }
+
+ public function getPrivateKey($client_id = '0')
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['public_key_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+ if ($result->count()==0) {
+ return false ;
+ }
+ $token = $this->dynamo2array($result);
+
+ return $token['private_key'];
+ }
+
+ public function getEncryptionAlgorithm($client_id = null)
+ {
+ $result = $this->client->getItem(array(
+ "TableName"=> $this->config['public_key_table'],
+ "Key" => array('client_id' => array('S' => $client_id))
+ ));
+ if ($result->count()==0) {
+ return 'RS256' ;
+ }
+ $token = $this->dynamo2array($result);
+
+ return $token['encryption_algorithm'];
+ }
+
+ /**
+ * Transform dynamodb resultset to an array.
+ * @param $dynamodbResult
+ * @return $array
+ */
+ private function dynamo2array($dynamodbResult)
+ {
+ $result = array();
+ foreach ($dynamodbResult["Item"] as $key => $val) {
+ $result[$key] = $val["S"];
+ $result[] = $val["S"];
+ }
+
+ return $result;
+ }
+}
diff --git a/src/OAuth2/Storage/Pdo.php b/src/OAuth2/Storage/Pdo.php
index 0cdd52e..17016e7 100644
--- a/src/OAuth2/Storage/Pdo.php
+++ b/src/OAuth2/Storage/Pdo.php
@@ -4,6 +4,7 @@ namespace OAuth2\Storage;
use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
+
/**
* Simple PDO storage for all storage types
*
@@ -16,7 +17,8 @@ use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeI
*
* @author Brent Shaffer <bshafs at gmail dot com>
*/
-class Pdo implements AuthorizationCodeInterface,
+class Pdo implements
+ AuthorizationCodeInterface,
AccessTokenInterface,
ClientCredentialsInterface,
UserCredentialsInterface,
@@ -242,7 +244,7 @@ class Pdo implements AuthorizationCodeInterface,
// address is an object with subfields
$userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
} else {
- $userClaims = array_merge($this->getUserClaim($validClaim, $userDetails));
+ $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
}
}
}
@@ -442,4 +444,84 @@ class Pdo implements AuthorizationCodeInterface,
return 'RS256';
}
+
+ /**
+ * DDL to create OAuth2 database and tables for PDO storage
+ *
+ * @see https://github.com/dsquier/oauth2-server-php-mysql
+ */
+ public function getBuildSql($dbName = 'oauth2_server_php')
+ {
+ $sql = "
+ CREATE TABLE {$this->config['client_table']} (
+ client_id VARCHAR(80) NOT NULL,
+ client_secret VARCHAR(80) NOT NULL,
+ redirect_uri VARCHAR(2000),
+ grant_types VARCHAR(80),
+ scope VARCHAR(4000),
+ user_id VARCHAR(80),
+ PRIMARY KEY (client_id)
+ );
+
+ CREATE TABLE {$this->config['access_token_table']} (
+ access_token VARCHAR(40) NOT NULL,
+ client_id VARCHAR(80) NOT NULL,
+ user_id VARCHAR(80),
+ expires TIMESTAMP NOT NULL,
+ scope VARCHAR(4000),
+ PRIMARY KEY (access_token)
+ );
+
+ CREATE TABLE {$this->config['code_table']} (
+ authorization_code VARCHAR(40) NOT NULL,
+ client_id VARCHAR(80) NOT NULL,
+ user_id VARCHAR(80),
+ redirect_uri VARCHAR(2000),
+ expires TIMESTAMP NOT NULL,
+ scope VARCHAR(4000),
+ id_token VARCHAR(1000),
+ PRIMARY KEY (authorization_code)
+ );
+
+ CREATE TABLE {$this->config['refresh_token_table']} (
+ refresh_token VARCHAR(40) NOT NULL,
+ client_id VARCHAR(80) NOT NULL,
+ user_id VARCHAR(80),
+ expires TIMESTAMP NOT NULL,
+ scope VARCHAR(4000),
+ PRIMARY KEY (refresh_token)
+ );
+
+ CREATE TABLE {$this->config['user_table']} (
+ username VARCHAR(80),
+ password VARCHAR(80),
+ first_name VARCHAR(80),
+ last_name VARCHAR(80),
+ email VARCHAR(80),
+ email_verified BOOLEAN,
+ scope VARCHAR(4000)
+ );
+
+ CREATE TABLE {$this->config['scope_table']} (
+ scope VARCHAR(80) NOT NULL,
+ is_default BOOLEAN,
+ PRIMARY KEY (scope)
+ );
+
+ CREATE TABLE {$this->config['jwt_table']} (
+ client_id VARCHAR(80) NOT NULL,
+ subject VARCHAR(80),
+ public_key VARCHAR(2000) NOT NULL
+ );
+
+ CREATE TABLE {$this->config['public_key_table']} (
+ client_id VARCHAR(80),
+ public_key VARCHAR(2000),
+ private_key VARCHAR(2000),
+ encryption_algorithm VARCHAR(100) DEFAULT 'RS256'
+ )
+";
+
+ return $sql;
+ }
}
diff --git a/src/OAuth2/Storage/ScopeInterface.php b/src/OAuth2/Storage/ScopeInterface.php
index e88ff7f..a829226 100644
--- a/src/OAuth2/Storage/ScopeInterface.php
+++ b/src/OAuth2/Storage/ScopeInterface.php
@@ -28,7 +28,7 @@ interface ScopeInterface
* request_error is returned by the server to force a
* scope request by the client. By returning "null",
* opt out of requiring scopes
- *
+ *
* @param $client_id
* An optional client id that can be used to return customized default scopes.
*
diff --git a/src/OAuth2/TokenType/Bearer.php b/src/OAuth2/TokenType/Bearer.php
index 0672572..0ec9fec 100644
--- a/src/OAuth2/TokenType/Bearer.php
+++ b/src/OAuth2/TokenType/Bearer.php
@@ -35,7 +35,7 @@ class Bearer implements TokenTypeInterface
$headers = $request->headers('AUTHORIZATION');
// check the header, then the querystring, then the request body
- return !empty($headers) || (bool)($request->request($this->config['token_param_name'])) || (bool)($request->query($this->config['token_param_name']));
+ return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name']));
}
/**
@@ -70,7 +70,7 @@ class Bearer implements TokenTypeInterface
*
* @see http://tools.ietf.org/html/rfc6750#section-3.1
*/
- $methodsUsed = !empty($headers) + (bool)($request->query($this->config['token_param_name'])) + (bool)($request->request($this->config['token_param_name']));
+ $methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name']));
if ($methodsUsed > 1) {
$response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)');