add composer's vendor directory
This commit is contained in:
parent
01a3860d73
commit
60b094d5fa
745 changed files with 56017 additions and 1 deletions
48
vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php
vendored
Normal file
48
vendor/bshaffer/oauth2-server-php/src/OAuth2/Autoloader.php
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
/**
|
||||
* Autoloads OAuth2 classes
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
* @license MIT License
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
private $dir;
|
||||
|
||||
public function __construct($dir = null)
|
||||
{
|
||||
if (is_null($dir)) {
|
||||
$dir = dirname(__FILE__).'/..';
|
||||
}
|
||||
$this->dir = $dir;
|
||||
}
|
||||
/**
|
||||
* Registers OAuth2\Autoloader as an SPL autoloader.
|
||||
*/
|
||||
public static function register($dir = null)
|
||||
{
|
||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||
spl_autoload_register(array(new self($dir), 'autoload'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles autoloading of classes.
|
||||
*
|
||||
* @param string $class A class name.
|
||||
*
|
||||
* @return boolean Returns true if the class has been loaded
|
||||
*/
|
||||
public function autoload($class)
|
||||
{
|
||||
if (0 !== strpos($class, 'OAuth2')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ClientAssertionType;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Interface for all OAuth2 Client Assertion Types
|
||||
*/
|
||||
interface ClientAssertionTypeInterface
|
||||
{
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response);
|
||||
public function getClientId();
|
||||
}
|
123
vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php
vendored
Normal file
123
vendor/bshaffer/oauth2-server-php/src/OAuth2/ClientAssertionType/HttpBasic.php
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ClientAssertionType;
|
||||
|
||||
use OAuth2\Storage\ClientCredentialsInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Validate a client via Http Basic authentication
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class HttpBasic implements ClientAssertionTypeInterface
|
||||
{
|
||||
private $clientData;
|
||||
|
||||
protected $storage;
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information
|
||||
* @param array $config OPTIONAL Configuration options for the server
|
||||
* <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())
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->config = array_merge(array(
|
||||
'allow_credentials_in_request_body' => true,
|
||||
'allow_public_clients' => true,
|
||||
), $config);
|
||||
}
|
||||
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$clientData = $this->getClientCredentials($request, $response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($clientData['client_id'])) {
|
||||
throw new \LogicException('the clientData array must have "client_id" set');
|
||||
}
|
||||
|
||||
if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') {
|
||||
if (!$this->config['allow_public_clients']) {
|
||||
$response->setError(400, 'invalid_client', 'client credentials are required');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->storage->isPublicClient($clientData['client_id'])) {
|
||||
$response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret');
|
||||
|
||||
return false;
|
||||
}
|
||||
} elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) {
|
||||
$response->setError(400, 'invalid_client', 'The client credentials are invalid');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->clientData = $clientData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->clientData['client_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function used to get the client credentials from HTTP basic
|
||||
* auth or POST data.
|
||||
*
|
||||
* According to the spec (draft 20), the client_id can be provided in
|
||||
* the Basic Authorization header (recommended) or via GET/POST.
|
||||
*
|
||||
* @return
|
||||
* A list containing the client identifier and password, for example
|
||||
* @code
|
||||
* return array(
|
||||
* "client_id" => CLIENT_ID, // REQUIRED the client id
|
||||
* "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients)
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
*
|
||||
* @ingroup oauth2_section_2
|
||||
*/
|
||||
public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) {
|
||||
return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW'));
|
||||
}
|
||||
|
||||
if ($this->config['allow_credentials_in_request_body']) {
|
||||
// Using POST for HttpBasic authorization is not recommended, but is supported by specification
|
||||
if (!is_null($request->request('client_id'))) {
|
||||
/**
|
||||
* client_secret can be null if the client's password is an empty string
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1
|
||||
*/
|
||||
|
||||
return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($response) {
|
||||
$message = $this->config['allow_credentials_in_request_body'] ? ' or body' : '';
|
||||
$response->setError(400, 'invalid_client', 'Client credentials were not found in the headers'.$message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
383
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php
vendored
Normal file
383
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeController.php
vendored
Normal file
|
@ -0,0 +1,383 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\Storage\ClientInterface;
|
||||
use OAuth2\ScopeInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
use OAuth2\Scope;
|
||||
|
||||
/**
|
||||
* @see OAuth2\Controller\AuthorizeControllerInterface
|
||||
*/
|
||||
class AuthorizeController implements AuthorizeControllerInterface
|
||||
{
|
||||
private $scope;
|
||||
private $state;
|
||||
private $client_id;
|
||||
private $redirect_uri;
|
||||
private $response_type;
|
||||
|
||||
protected $clientStorage;
|
||||
protected $responseTypes;
|
||||
protected $config;
|
||||
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
|
||||
* );
|
||||
* </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)
|
||||
{
|
||||
$this->clientStorage = $clientStorage;
|
||||
$this->responseTypes = $responseTypes;
|
||||
$this->config = array_merge(array(
|
||||
'allow_implicit' => false,
|
||||
'enforce_state' => true,
|
||||
'require_exact_redirect_uri' => true,
|
||||
'redirect_status_code' => 302,
|
||||
), $config);
|
||||
|
||||
if (is_null($scopeUtil)) {
|
||||
$scopeUtil = new Scope();
|
||||
}
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
}
|
||||
|
||||
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
|
||||
{
|
||||
if (!is_bool($is_authorized)) {
|
||||
throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
|
||||
}
|
||||
|
||||
// We repeat this, because we need to re-validate. The request could be POSTed
|
||||
// by a 3rd-party (because we are not internally enforcing NONCEs, etc)
|
||||
if (!$this->validateAuthorizeRequest($request, $response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no redirect_uri is passed in the request, use client's registered one
|
||||
if (empty($this->redirect_uri)) {
|
||||
$clientData = $this->clientStorage->getClientDetails($this->client_id);
|
||||
$registered_redirect_uri = $clientData['redirect_uri'];
|
||||
}
|
||||
|
||||
// the user declined access to the client's application
|
||||
if ($is_authorized === false) {
|
||||
$redirect_uri = $this->redirect_uri ?: $registered_redirect_uri;
|
||||
$this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// build the parameters to set in the redirect URI
|
||||
if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id);
|
||||
|
||||
list($redirect_uri, $uri_params) = $authResult;
|
||||
|
||||
if (empty($redirect_uri) && !empty($registered_redirect_uri)) {
|
||||
$redirect_uri = $registered_redirect_uri;
|
||||
}
|
||||
|
||||
$uri = $this->buildUri($redirect_uri, $uri_params);
|
||||
|
||||
// return redirect response
|
||||
$response->setRedirect($this->config['redirect_status_code'], $uri);
|
||||
}
|
||||
|
||||
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
|
||||
{
|
||||
$error = 'access_denied';
|
||||
$error_message = 'The user denied access to your application';
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have made this protected so this class can be extended to add/modify
|
||||
* these parameters
|
||||
*/
|
||||
protected function buildAuthorizeParameters($request, $response, $user_id)
|
||||
{
|
||||
// @TODO: we should be explicit with this in the future
|
||||
$params = array(
|
||||
'scope' => $this->scope,
|
||||
'state' => $this->state,
|
||||
'client_id' => $this->client_id,
|
||||
'redirect_uri' => $this->redirect_uri,
|
||||
'response_type' => $this->response_type,
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
// Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI)
|
||||
if (!$client_id = $request->query('client_id', $request->request('client_id'))) {
|
||||
// We don't have a good URI to use
|
||||
$response->setError(400, 'invalid_client', "No client id supplied");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get client details
|
||||
if (!$clientData = $this->clientStorage->getClientDetails($client_id)) {
|
||||
$response->setError(400, 'invalid_client', 'The client id supplied is invalid');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : '';
|
||||
|
||||
// Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI.
|
||||
// @see http://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||
// @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
// @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1
|
||||
if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) {
|
||||
// validate there is no fragment supplied
|
||||
$parts = parse_url($supplied_redirect_uri);
|
||||
if (isset($parts['fragment']) && $parts['fragment']) {
|
||||
$response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate against the registered redirect uri(s) if available
|
||||
if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) {
|
||||
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2');
|
||||
|
||||
return false;
|
||||
}
|
||||
$redirect_uri = $supplied_redirect_uri;
|
||||
} else {
|
||||
// use the registered redirect_uri if none has been supplied, if possible
|
||||
if (!$registered_redirect_uri) {
|
||||
$response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count(explode(' ', $registered_redirect_uri)) > 1) {
|
||||
$response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3');
|
||||
|
||||
return false;
|
||||
}
|
||||
$redirect_uri = $registered_redirect_uri;
|
||||
}
|
||||
|
||||
// Select the redirect URI
|
||||
$response_type = $request->query('response_type', $request->request('response_type'));
|
||||
|
||||
// for multiple-valued response types - make them alphabetical
|
||||
if (false !== strpos($response_type, ' ')) {
|
||||
$types = explode(' ', $response_type);
|
||||
sort($types);
|
||||
$response_type = ltrim(implode(' ', $types));
|
||||
}
|
||||
|
||||
$state = $request->query('state', $request->request('state'));
|
||||
|
||||
// type and client_id are required
|
||||
if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
|
||||
if (!isset($this->responseTypes['code'])) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) {
|
||||
$response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied');
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!$this->config['allow_implicit']) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// validate requested scope if it exists
|
||||
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
|
||||
|
||||
if ($requestedScope) {
|
||||
// restrict scope by client specific scope if applicable,
|
||||
// otherwise verify the scope exists
|
||||
$clientScope = $this->clientStorage->getClientScope($client_id);
|
||||
if ((is_null($clientScope) && !$this->scopeUtil->scopeExists($requestedScope))
|
||||
|| ($clientScope && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// use a globally-defined default scope
|
||||
$defaultScope = $this->scopeUtil->getDefaultScope($client_id);
|
||||
|
||||
if (false === $defaultScope) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$requestedScope = $defaultScope;
|
||||
}
|
||||
|
||||
// Validate state parameter exists (if configured to enforce this)
|
||||
if ($this->config['enforce_state'] && !$state) {
|
||||
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// save the input data and return true
|
||||
$this->scope = $requestedScope;
|
||||
$this->state = $state;
|
||||
$this->client_id = $client_id;
|
||||
// Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3)
|
||||
$this->redirect_uri = $supplied_redirect_uri;
|
||||
$this->response_type = $response_type;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the absolute URI based on supplied URI and parameters.
|
||||
*
|
||||
* @param $uri An absolute URI.
|
||||
* @param $params Parameters to be append as GET.
|
||||
*
|
||||
* @return
|
||||
* An absolute URI with supplied parameters.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
private function buildUri($uri, $params)
|
||||
{
|
||||
$parse_url = parse_url($uri);
|
||||
|
||||
// Add our params to the parsed uri
|
||||
foreach ($params as $k => $v) {
|
||||
if (isset($parse_url[$k])) {
|
||||
$parse_url[$k] .= "&" . http_build_query($v, '', '&');
|
||||
} else {
|
||||
$parse_url[$k] = http_build_query($v, '', '&');
|
||||
}
|
||||
}
|
||||
|
||||
// Put humpty dumpty back together
|
||||
return
|
||||
((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
|
||||
. ((isset($parse_url["user"])) ? $parse_url["user"]
|
||||
. ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
|
||||
. ((isset($parse_url["host"])) ? $parse_url["host"] : "")
|
||||
. ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "")
|
||||
. ((isset($parse_url["path"])) ? $parse_url["path"] : "")
|
||||
. ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "")
|
||||
. ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "")
|
||||
;
|
||||
}
|
||||
|
||||
protected function getValidResponseTypes()
|
||||
{
|
||||
return array(
|
||||
self::RESPONSE_TYPE_ACCESS_TOKEN,
|
||||
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for validating redirect URI supplied
|
||||
*
|
||||
* @param string $inputUri The submitted URI to be validated
|
||||
* @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
|
||||
* allow for multiple URIs
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
|
||||
*/
|
||||
protected function validateRedirectUri($inputUri, $registeredUriString)
|
||||
{
|
||||
if (!$inputUri || !$registeredUriString) {
|
||||
return false; // if either one is missing, assume INVALID
|
||||
}
|
||||
|
||||
$registered_uris = preg_split('/\s+/', $registeredUriString);
|
||||
foreach ($registered_uris as $registered_uri) {
|
||||
if ($this->config['require_exact_redirect_uri']) {
|
||||
// the input uri is validated against the registered uri using exact match
|
||||
if (strcmp($inputUri, $registered_uri) === 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// the input uri is validated against the registered uri using case-insensitive match of the initial string
|
||||
// i.e. additional query parameters may be applied
|
||||
if (strcasecmp(substr($inputUri, 0, strlen($registered_uri)), $registered_uri) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience methods to access the parameters derived from the validated request
|
||||
*/
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->client_id;
|
||||
}
|
||||
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirect_uri;
|
||||
}
|
||||
|
||||
public function getResponseType()
|
||||
{
|
||||
return $this->response_type;
|
||||
}
|
||||
}
|
43
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php
vendored
Normal file
43
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/AuthorizeControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This controller is called when a user should be authorized
|
||||
* by an authorization server. As OAuth2 does not handle
|
||||
* authorization directly, this controller ensures the request is valid, but
|
||||
* requires the application to determine the value of $is_authorized
|
||||
*
|
||||
* ex:
|
||||
* > $user_id = $this->somehowDetermineUserId();
|
||||
* > $is_authorized = $this->somehowDetermineUserAuthorization();
|
||||
* > $response = new OAuth2\Response();
|
||||
* > $authorizeController->handleAuthorizeRequest(
|
||||
* > OAuth2\Request::createFromGlobals(),
|
||||
* > $response,
|
||||
* > $is_authorized,
|
||||
* > $user_id);
|
||||
* > $response->send();
|
||||
*
|
||||
*/
|
||||
interface AuthorizeControllerInterface
|
||||
{
|
||||
/**
|
||||
* List of possible authentication response types.
|
||||
* The "authorization_code" mechanism exclusively supports 'code'
|
||||
* and the "implicit" mechanism exclusively supports 'token'.
|
||||
*
|
||||
* @var string
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.2.1
|
||||
*/
|
||||
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
|
||||
const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
|
||||
|
||||
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
|
||||
|
||||
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
|
||||
}
|
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php
vendored
Normal file
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceController.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\TokenType\TokenTypeInterface;
|
||||
use OAuth2\Storage\AccessTokenInterface;
|
||||
use OAuth2\ScopeInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
use OAuth2\Scope;
|
||||
|
||||
/**
|
||||
* @see OAuth2\Controller\ResourceControllerInterface
|
||||
*/
|
||||
class ResourceController implements ResourceControllerInterface
|
||||
{
|
||||
private $token;
|
||||
|
||||
protected $tokenType;
|
||||
protected $tokenStorage;
|
||||
protected $config;
|
||||
protected $scopeUtil;
|
||||
|
||||
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
|
||||
{
|
||||
$this->tokenType = $tokenType;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'www_realm' => 'Service',
|
||||
), $config);
|
||||
|
||||
if (is_null($scopeUtil)) {
|
||||
$scopeUtil = new Scope();
|
||||
}
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
}
|
||||
|
||||
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
|
||||
{
|
||||
$token = $this->getAccessTokenData($request, $response);
|
||||
|
||||
// Check if we have token data
|
||||
if (is_null($token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check scope, if provided
|
||||
* If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-3.1
|
||||
*/
|
||||
if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) {
|
||||
$response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token');
|
||||
$response->addHttpHeaders(array(
|
||||
'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"',
|
||||
$this->tokenType->getTokenType(),
|
||||
$this->config['www_realm'],
|
||||
$scope,
|
||||
$response->getParameter('error'),
|
||||
$response->getParameter('error_description')
|
||||
)
|
||||
));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// allow retrieval of the token
|
||||
$this->token = $token;
|
||||
|
||||
return (bool) $token;
|
||||
}
|
||||
|
||||
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
// Get the token parameter
|
||||
if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) {
|
||||
// Get the stored token data (from the implementing subclass)
|
||||
// Check we have a well formed token
|
||||
// Check token expiration (expires is a mandatory paramter)
|
||||
if (!$token = $this->tokenStorage->getAccessToken($token_param)) {
|
||||
$response->setError(401, 'invalid_token', 'The access token provided is invalid');
|
||||
} elseif (!isset($token["expires"]) || !isset($token["client_id"])) {
|
||||
$response->setError(401, 'malformed_token', 'Malformed token (missing "expires")');
|
||||
} elseif (time() > $token["expires"]) {
|
||||
$response->setError(401, 'expired_token', 'The access token provided has expired');
|
||||
} else {
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
|
||||
$authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']);
|
||||
|
||||
if ($error = $response->getParameter('error')) {
|
||||
$authHeader = sprintf('%s, error="%s"', $authHeader, $error);
|
||||
if ($error_description = $response->getParameter('error_description')) {
|
||||
$authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description);
|
||||
}
|
||||
}
|
||||
|
||||
$response->addHttpHeaders(array('WWW-Authenticate' => $authHeader));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// convenience method to allow retrieval of the token
|
||||
public function getToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
}
|
26
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php
vendored
Normal file
26
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/ResourceControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This controller is called when a "resource" is requested.
|
||||
* call verifyResourceRequest in order to determine if the request
|
||||
* contains a valid token.
|
||||
*
|
||||
* ex:
|
||||
* > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
|
||||
* > $response->send(); // authorization failed
|
||||
* > die();
|
||||
* > }
|
||||
* > return json_encode($resource); // valid token! Send the stuff!
|
||||
*
|
||||
*/
|
||||
interface ResourceControllerInterface
|
||||
{
|
||||
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
|
||||
|
||||
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
|
||||
}
|
274
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php
vendored
Normal file
274
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenController.php
vendored
Normal file
|
@ -0,0 +1,274 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||
use OAuth2\GrantType\GrantTypeInterface;
|
||||
use OAuth2\ScopeInterface;
|
||||
use OAuth2\Scope;
|
||||
use OAuth2\Storage\ClientInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @see OAuth2\Controller\TokenControllerInterface
|
||||
*/
|
||||
class TokenController implements TokenControllerInterface
|
||||
{
|
||||
protected $accessToken;
|
||||
protected $grantTypes;
|
||||
protected $clientAssertionType;
|
||||
protected $scopeUtil;
|
||||
protected $clientStorage;
|
||||
|
||||
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
|
||||
{
|
||||
if (is_null($clientAssertionType)) {
|
||||
foreach ($grantTypes as $grantType) {
|
||||
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||
throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->clientAssertionType = $clientAssertionType;
|
||||
$this->accessToken = $accessToken;
|
||||
$this->clientStorage = $clientStorage;
|
||||
foreach ($grantTypes as $grantType) {
|
||||
$this->addGrantType($grantType);
|
||||
}
|
||||
|
||||
if (is_null($scopeUtil)) {
|
||||
$scopeUtil = new Scope();
|
||||
}
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
}
|
||||
|
||||
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if ($token = $this->grantAccessToken($request, $response)) {
|
||||
// @see http://tools.ietf.org/html/rfc6749#section-5.1
|
||||
// server MUST disable caching in headers when tokens are involved
|
||||
$response->setStatusCode(200);
|
||||
$response->addParameters($token);
|
||||
$response->addHttpHeaders(array('Cache-Control' => 'no-store', 'Pragma' => 'no-cache'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant or deny a requested access token.
|
||||
* This would be called from the "/token" endpoint as defined in the spec.
|
||||
* You can call your endpoint whatever you want.
|
||||
*
|
||||
* @param $request - RequestInterface
|
||||
* Request object to grant access token
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws LogicException
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-10.6
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
|
||||
$response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
|
||||
$response->addHttpHeaders(array('Allow' => 'POST'));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine grant type from request
|
||||
* and validate the request for that grant type
|
||||
*/
|
||||
if (!$grantTypeIdentifier = $request->request('grant_type')) {
|
||||
$response->setError(400, 'invalid_request', 'The grant type was not specified in the request');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($this->grantTypes[$grantTypeIdentifier])) {
|
||||
/* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */
|
||||
$response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$grantType = $this->grantTypes[$grantTypeIdentifier];
|
||||
|
||||
/**
|
||||
* Retrieve the client information from the request
|
||||
* ClientAssertionTypes allow for grant types which also assert the client data
|
||||
* in which case ClientAssertion is handled in the validateRequest method
|
||||
*
|
||||
* @see OAuth2\GrantType\JWTBearer
|
||||
* @see OAuth2\GrantType\ClientCredentials
|
||||
*/
|
||||
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||
if (!$this->clientAssertionType->validateRequest($request, $response)) {
|
||||
return null;
|
||||
}
|
||||
$clientId = $this->clientAssertionType->getClientId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the grant type information from the request
|
||||
* The GrantTypeInterface object handles all validation
|
||||
* If the object is an instance of ClientAssertionTypeInterface,
|
||||
* That logic is handled here as well
|
||||
*/
|
||||
if (!$grantType->validateRequest($request, $response)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($grantType instanceof ClientAssertionTypeInterface) {
|
||||
$clientId = $grantType->getClientId();
|
||||
} else {
|
||||
// validate the Client ID (if applicable)
|
||||
if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) {
|
||||
$response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client can use the requested grant type
|
||||
*/
|
||||
if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) {
|
||||
$response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the scope of the token
|
||||
*
|
||||
* requestedScope - the scope specified in the token request
|
||||
* availableScope - the scope associated with the grant type
|
||||
* ex: in the case of the "Authorization Code" grant type,
|
||||
* the scope is specified in the authorize request
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-3.3
|
||||
*/
|
||||
|
||||
$requestedScope = $this->scopeUtil->getScopeFromRequest($request);
|
||||
$availableScope = $grantType->getScope();
|
||||
|
||||
if ($requestedScope) {
|
||||
// validate the requested scope
|
||||
if ($availableScope) {
|
||||
if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) {
|
||||
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request');
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// validate the client has access to this scope
|
||||
if ($clientScope = $this->clientStorage->getClientScope($clientId)) {
|
||||
if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) {
|
||||
$response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client');
|
||||
|
||||
return false;
|
||||
}
|
||||
} elseif (!$this->scopeUtil->scopeExists($requestedScope)) {
|
||||
$response->setError(400, 'invalid_scope', 'An unsupported scope was requested');
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} elseif ($availableScope) {
|
||||
// use the scope associated with this grant type
|
||||
$requestedScope = $availableScope;
|
||||
} else {
|
||||
// use a globally-defined default scope
|
||||
$defaultScope = $this->scopeUtil->getDefaultScope($clientId);
|
||||
|
||||
// "false" means default scopes are not allowed
|
||||
if (false === $defaultScope) {
|
||||
$response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$requestedScope = $defaultScope;
|
||||
}
|
||||
|
||||
return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* addGrantType
|
||||
*
|
||||
* @param grantType - OAuth2\GrantTypeInterface
|
||||
* the grant type to add for the specified identifier
|
||||
* @param identifier - string
|
||||
* a string passed in as "grant_type" in the response that will call this grantType
|
||||
*/
|
||||
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||
{
|
||||
if (is_null($identifier) || is_numeric($identifier)) {
|
||||
$identifier = $grantType->getQuerystringIdentifier();
|
||||
}
|
||||
|
||||
$this->grantTypes[$identifier] = $grantType;
|
||||
}
|
||||
|
||||
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if ($this->revokeToken($request, $response)) {
|
||||
$response->setStatusCode(200);
|
||||
$response->addParameters(array('revoked' => true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a refresh or access token. Returns true on success and when tokens are invalid
|
||||
*
|
||||
* Note: invalid tokens do not cause an error response since the client
|
||||
* cannot handle such an error in a reasonable way. Moreover, the
|
||||
* purpose of the revocation request, invalidating the particular token,
|
||||
* is already achieved.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return bool|null
|
||||
*/
|
||||
public function revokeToken(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
|
||||
$response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
|
||||
$response->addHttpHeaders(array('Allow' => 'POST'));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$token_type_hint = $request->request('token_type_hint');
|
||||
if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) {
|
||||
$response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\'');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$token = $request->request('token');
|
||||
if ($token === null) {
|
||||
$response->setError(400, 'invalid_request', 'Missing token parameter to revoke');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// @todo remove this check for v2.0
|
||||
if (!method_exists($this->accessToken, 'revokeToken')) {
|
||||
$class = get_class($this->accessToken);
|
||||
throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method");
|
||||
}
|
||||
|
||||
$this->accessToken->revokeToken($token, $token_type_hint);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
32
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php
vendored
Normal file
32
vendor/bshaffer/oauth2-server-php/src/OAuth2/Controller/TokenControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Controller;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This controller is called when a token is being requested.
|
||||
* it is called to handle all grant types the application supports.
|
||||
* It also validates the client's credentials
|
||||
*
|
||||
* ex:
|
||||
* > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
|
||||
* > $response->send();
|
||||
*
|
||||
*/
|
||||
interface TokenControllerInterface
|
||||
{
|
||||
/**
|
||||
* handleTokenRequest
|
||||
*
|
||||
* @param $request
|
||||
* OAuth2\RequestInterface - The current http request
|
||||
* @param $response
|
||||
* OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
|
||||
*
|
||||
*/
|
||||
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
|
||||
|
||||
public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
|
||||
}
|
11
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php
vendored
Normal file
11
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/EncryptionInterface.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Encryption;
|
||||
|
||||
interface EncryptionInterface
|
||||
{
|
||||
public function encode($payload, $key, $algorithm = null);
|
||||
public function decode($payload, $key, $algorithm = null);
|
||||
public function urlSafeB64Encode($data);
|
||||
public function urlSafeB64Decode($b64);
|
||||
}
|
47
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php
vendored
Normal file
47
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/FirebaseJwt.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Encryption;
|
||||
|
||||
/**
|
||||
* Bridge file to use the firebase/php-jwt package for JWT encoding and decoding.
|
||||
* @author Francis Chuang <francis.chuang@gmail.com>
|
||||
*/
|
||||
class FirebaseJwt implements EncryptionInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (!class_exists('\JWT')) {
|
||||
throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"');
|
||||
}
|
||||
}
|
||||
|
||||
public function encode($payload, $key, $alg = 'HS256', $keyId = null)
|
||||
{
|
||||
return \JWT::encode($payload, $key, $alg, $keyId);
|
||||
}
|
||||
|
||||
public function decode($jwt, $key = null, $allowedAlgorithms = null)
|
||||
{
|
||||
try {
|
||||
|
||||
//Maintain BC: Do not verify if no algorithms are passed in.
|
||||
if (!$allowedAlgorithms) {
|
||||
$key = null;
|
||||
}
|
||||
|
||||
return (array)\JWT::decode($jwt, $key, $allowedAlgorithms);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function urlSafeB64Encode($data)
|
||||
{
|
||||
return \JWT::urlsafeB64Encode($data);
|
||||
}
|
||||
|
||||
public function urlSafeB64Decode($b64)
|
||||
{
|
||||
return \JWT::urlsafeB64Decode($b64);
|
||||
}
|
||||
}
|
173
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php
vendored
Normal file
173
vendor/bshaffer/oauth2-server-php/src/OAuth2/Encryption/Jwt.php
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Encryption;
|
||||
|
||||
/**
|
||||
* @link https://github.com/F21/jwt
|
||||
* @author F21
|
||||
*/
|
||||
class Jwt implements EncryptionInterface
|
||||
{
|
||||
public function encode($payload, $key, $algo = 'HS256')
|
||||
{
|
||||
$header = $this->generateJwtHeader($payload, $algo);
|
||||
|
||||
$segments = array(
|
||||
$this->urlSafeB64Encode(json_encode($header)),
|
||||
$this->urlSafeB64Encode(json_encode($payload))
|
||||
);
|
||||
|
||||
$signing_input = implode('.', $segments);
|
||||
|
||||
$signature = $this->sign($signing_input, $key, $algo);
|
||||
$segments[] = $this->urlsafeB64Encode($signature);
|
||||
|
||||
return implode('.', $segments);
|
||||
}
|
||||
|
||||
public function decode($jwt, $key = null, $allowedAlgorithms = true)
|
||||
{
|
||||
if (!strpos($jwt, '.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tks = explode('.', $jwt);
|
||||
|
||||
if (count($tks) != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($headb64, $payloadb64, $cryptob64) = $tks;
|
||||
|
||||
if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sig = $this->urlSafeB64Decode($cryptob64);
|
||||
|
||||
if ((bool) $allowedAlgorithms) {
|
||||
if (!isset($header['alg'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if bool arg supplied here to maintain BC
|
||||
if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function verifySignature($signature, $input, $key, $algo = 'HS256')
|
||||
{
|
||||
// use constants when possible, for HipHop support
|
||||
switch ($algo) {
|
||||
case'HS256':
|
||||
case'HS384':
|
||||
case'HS512':
|
||||
return $this->hash_equals(
|
||||
$this->sign($input, $key, $algo),
|
||||
$signature
|
||||
);
|
||||
|
||||
case 'RS256':
|
||||
return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1;
|
||||
|
||||
case 'RS384':
|
||||
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1;
|
||||
|
||||
case 'RS512':
|
||||
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unsupported or invalid signing algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
private function sign($input, $key, $algo = 'HS256')
|
||||
{
|
||||
switch ($algo) {
|
||||
case 'HS256':
|
||||
return hash_hmac('sha256', $input, $key, true);
|
||||
|
||||
case 'HS384':
|
||||
return hash_hmac('sha384', $input, $key, true);
|
||||
|
||||
case 'HS512':
|
||||
return hash_hmac('sha512', $input, $key, true);
|
||||
|
||||
case 'RS256':
|
||||
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256');
|
||||
|
||||
case 'RS384':
|
||||
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384');
|
||||
|
||||
case 'RS512':
|
||||
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
|
||||
|
||||
default:
|
||||
throw new \Exception("Unsupported or invalid signing algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
private function generateRSASignature($input, $key, $algo)
|
||||
{
|
||||
if (!openssl_sign($input, $signature, $key, $algo)) {
|
||||
throw new \Exception("Unable to sign data.");
|
||||
}
|
||||
|
||||
return $signature;
|
||||
}
|
||||
|
||||
public function urlSafeB64Encode($data)
|
||||
{
|
||||
$b64 = base64_encode($data);
|
||||
$b64 = str_replace(array('+', '/', "\r", "\n", '='),
|
||||
array('-', '_'),
|
||||
$b64);
|
||||
|
||||
return $b64;
|
||||
}
|
||||
|
||||
public function urlSafeB64Decode($b64)
|
||||
{
|
||||
$b64 = str_replace(array('-', '_'),
|
||||
array('+', '/'),
|
||||
$b64);
|
||||
|
||||
return base64_decode($b64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to create a custom header
|
||||
*/
|
||||
protected function generateJwtHeader($payload, $algorithm)
|
||||
{
|
||||
return array(
|
||||
'typ' => 'JWT',
|
||||
'alg' => $algorithm,
|
||||
);
|
||||
}
|
||||
|
||||
protected function hash_equals($a, $b)
|
||||
{
|
||||
if (function_exists('hash_equals')) {
|
||||
return hash_equals($a, $b);
|
||||
}
|
||||
$diff = strlen($a) ^ strlen($b);
|
||||
for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) {
|
||||
$diff |= ord($a[$i]) ^ ord($b[$i]);
|
||||
}
|
||||
|
||||
return $diff === 0;
|
||||
}
|
||||
}
|
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php
vendored
Normal file
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\Storage\AuthorizationCodeInterface;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class AuthorizationCode implements GrantTypeInterface
|
||||
{
|
||||
protected $storage;
|
||||
protected $authCode;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information
|
||||
*/
|
||||
public function __construct(AuthorizationCodeInterface $storage)
|
||||
{
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
public function getQuerystringIdentifier()
|
||||
{
|
||||
return 'authorization_code';
|
||||
}
|
||||
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$request->request('code')) {
|
||||
$response->setError(400, 'invalid_request', 'Missing parameter: "code" is required');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$code = $request->request('code');
|
||||
if (!$authCode = $this->storage->getAuthorizationCode($code)) {
|
||||
$response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request
|
||||
* @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*/
|
||||
if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) {
|
||||
if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) {
|
||||
$response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($authCode['expires'])) {
|
||||
throw new \Exception('Storage must return authcode with a value for "expires"');
|
||||
}
|
||||
|
||||
if ($authCode["expires"] < time()) {
|
||||
$response->setError(400, 'invalid_grant', "The authorization code has expired");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($authCode['code'])) {
|
||||
$authCode['code'] = $code; // used to expire the code after the access token is granted
|
||||
}
|
||||
|
||||
$this->authCode = $authCode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->authCode['client_id'];
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return isset($this->authCode['scope']) ? $this->authCode['scope'] : null;
|
||||
}
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null;
|
||||
}
|
||||
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
$token = $accessToken->createAccessToken($client_id, $user_id, $scope);
|
||||
$this->storage->expireAuthorizationCode($this->authCode['code']);
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
67
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php
vendored
Normal file
67
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/ClientCredentials.php
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\ClientAssertionType\HttpBasic;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\Storage\ClientCredentialsInterface;
|
||||
|
||||
/**
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*
|
||||
* @see OAuth2\ClientAssertionType_HttpBasic
|
||||
*/
|
||||
class ClientCredentials extends HttpBasic implements GrantTypeInterface
|
||||
{
|
||||
private $clientData;
|
||||
|
||||
public function __construct(ClientCredentialsInterface $storage, array $config = array())
|
||||
{
|
||||
/**
|
||||
* The client credentials grant type MUST only be used by confidential clients
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.4
|
||||
*/
|
||||
$config['allow_public_clients'] = false;
|
||||
|
||||
parent::__construct($storage, $config);
|
||||
}
|
||||
|
||||
public function getQuerystringIdentifier()
|
||||
{
|
||||
return 'client_credentials';
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
$this->loadClientData();
|
||||
|
||||
return isset($this->clientData['scope']) ? $this->clientData['scope'] : null;
|
||||
}
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
$this->loadClientData();
|
||||
|
||||
return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null;
|
||||
}
|
||||
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
/**
|
||||
* Client Credentials Grant does NOT include a refresh token
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.4.3
|
||||
*/
|
||||
$includeRefreshToken = false;
|
||||
|
||||
return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||
}
|
||||
|
||||
private function loadClientData()
|
||||
{
|
||||
if (!$this->clientData) {
|
||||
$this->clientData = $this->storage->getClientDetails($this->getClientId());
|
||||
}
|
||||
}
|
||||
}
|
20
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php
vendored
Normal file
20
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/GrantTypeInterface.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Interface for all OAuth2 Grant Types
|
||||
*/
|
||||
interface GrantTypeInterface
|
||||
{
|
||||
public function getQuerystringIdentifier();
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response);
|
||||
public function getClientId();
|
||||
public function getUserId();
|
||||
public function getScope();
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope);
|
||||
}
|
226
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
vendored
Normal file
226
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||
use OAuth2\Storage\JwtBearerInterface;
|
||||
use OAuth2\Encryption\Jwt;
|
||||
use OAuth2\Encryption\EncryptionInterface;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4
|
||||
*
|
||||
* @author F21
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
|
||||
{
|
||||
private $jwt;
|
||||
|
||||
protected $storage;
|
||||
protected $audience;
|
||||
protected $jwtUtil;
|
||||
protected $allowedAlgorithms;
|
||||
|
||||
/**
|
||||
* Creates an instance of the JWT bearer grant type.
|
||||
*
|
||||
* @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
|
||||
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
|
||||
* @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->audience = $audience;
|
||||
|
||||
if (is_null($jwtUtil)) {
|
||||
$jwtUtil = new Jwt();
|
||||
}
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
|
||||
), $config);
|
||||
|
||||
$this->jwtUtil = $jwtUtil;
|
||||
|
||||
$this->allowedAlgorithms = $this->config['allowed_algorithms'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
|
||||
*
|
||||
* @return
|
||||
* The string identifier for grant_type.
|
||||
*
|
||||
* @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier()
|
||||
*/
|
||||
public function getQuerystringIdentifier()
|
||||
{
|
||||
return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the data from the decoded JWT.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.
|
||||
*
|
||||
* @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
|
||||
*/
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$request->request("assertion")) {
|
||||
$response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Store the undecoded JWT for later use
|
||||
$undecodedJWT = $request->request('assertion');
|
||||
|
||||
// Decode the JWT
|
||||
$jwt = $this->jwtUtil->decode($request->request('assertion'), null, false);
|
||||
|
||||
if (!$jwt) {
|
||||
$response->setError(400, 'invalid_request', "JWT is malformed");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ensure these properties contain a value
|
||||
// @todo: throw malformed error for missing properties
|
||||
$jwt = array_merge(array(
|
||||
'scope' => null,
|
||||
'iss' => null,
|
||||
'sub' => null,
|
||||
'aud' => null,
|
||||
'exp' => null,
|
||||
'nbf' => null,
|
||||
'iat' => null,
|
||||
'jti' => null,
|
||||
'typ' => null,
|
||||
), $jwt);
|
||||
|
||||
if (!isset($jwt['iss'])) {
|
||||
$response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($jwt['sub'])) {
|
||||
$response->setError(400, 'invalid_grant', "Invalid subject (sub) provided");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($jwt['exp'])) {
|
||||
$response->setError(400, 'invalid_grant', "Expiration (exp) time must be present");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check expiration
|
||||
if (ctype_digit($jwt['exp'])) {
|
||||
if ($jwt['exp'] <= time()) {
|
||||
$response->setError(400, 'invalid_grant', "JWT has expired");
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
$response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the not before time
|
||||
if ($notBefore = $jwt['nbf']) {
|
||||
if (ctype_digit($notBefore)) {
|
||||
if ($notBefore > time()) {
|
||||
$response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time");
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
$response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the audience if required to match
|
||||
if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) {
|
||||
$response->setError(400, 'invalid_grant', "Invalid audience (aud)");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the jti (nonce)
|
||||
// @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7
|
||||
if (isset($jwt['jti'])) {
|
||||
$jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
|
||||
|
||||
//Reject if jti is used and jwt is still valid (exp parameter has not expired).
|
||||
if ($jti && $jti['expires'] > time()) {
|
||||
$response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used");
|
||||
|
||||
return null;
|
||||
} else {
|
||||
$this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the iss's public key
|
||||
// @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1
|
||||
if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) {
|
||||
$response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify the JWT
|
||||
if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) {
|
||||
$response->setError(400, 'invalid_grant', "JWT failed signature verification");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->jwt = $jwt;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->jwt['iss'];
|
||||
}
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->jwt['sub'];
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an access token that is NOT associated with a refresh token.
|
||||
* If a subject (sub) the name of the user/account we are accessing data on behalf of.
|
||||
*
|
||||
* @see OAuth2\GrantType\GrantTypeInterface::createAccessToken()
|
||||
*/
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
$includeRefreshToken = false;
|
||||
|
||||
return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||
}
|
||||
}
|
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php
vendored
Normal file
111
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/RefreshToken.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\Storage\RefreshTokenInterface;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class RefreshToken implements GrantTypeInterface
|
||||
{
|
||||
private $refreshToken;
|
||||
|
||||
protected $storage;
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information
|
||||
* @param array $config OPTIONAL Configuration options for the server
|
||||
* <code>
|
||||
* $config = array(
|
||||
* 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
|
||||
* 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
public function __construct(RefreshTokenInterface $storage, $config = array())
|
||||
{
|
||||
$this->config = array_merge(array(
|
||||
'always_issue_new_refresh_token' => false,
|
||||
'unset_refresh_token_after_use' => true
|
||||
), $config);
|
||||
|
||||
// to preserve B.C. with v1.6
|
||||
// @see https://github.com/bshaffer/oauth2-server-php/pull/580
|
||||
// @todo - remove in v2.0
|
||||
if (isset($config['always_issue_new_refresh_token']) && !isset($config['unset_refresh_token_after_use'])) {
|
||||
$this->config['unset_refresh_token_after_use'] = $config['always_issue_new_refresh_token'];
|
||||
}
|
||||
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
public function getQuerystringIdentifier()
|
||||
{
|
||||
return 'refresh_token';
|
||||
}
|
||||
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$request->request("refresh_token")) {
|
||||
$response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$refreshToken = $this->storage->getRefreshToken($request->request("refresh_token"))) {
|
||||
$response->setError(400, 'invalid_grant', 'Invalid refresh token');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) {
|
||||
$response->setError(400, 'invalid_grant', 'Refresh token has expired');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// store the refresh token locally so we can delete it when a new refresh token is generated
|
||||
$this->refreshToken = $refreshToken;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->refreshToken['client_id'];
|
||||
}
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null;
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
|
||||
}
|
||||
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
/*
|
||||
* It is optional to force a new refresh token when a refresh token is used.
|
||||
* However, if a new refresh token is issued, the old one MUST be expired
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-6
|
||||
*/
|
||||
$issueNewRefreshToken = $this->config['always_issue_new_refresh_token'];
|
||||
$unsetRefreshToken = $this->config['unset_refresh_token_after_use'];
|
||||
$token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken);
|
||||
|
||||
if ($unsetRefreshToken) {
|
||||
$this->storage->unsetRefreshToken($this->refreshToken['refresh_token']);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
83
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php
vendored
Normal file
83
vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/UserCredentials.php
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\GrantType;
|
||||
|
||||
use OAuth2\Storage\UserCredentialsInterface;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class UserCredentials implements GrantTypeInterface
|
||||
{
|
||||
private $userInfo;
|
||||
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information
|
||||
*/
|
||||
public function __construct(UserCredentialsInterface $storage)
|
||||
{
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
public function getQuerystringIdentifier()
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
|
||||
public function validateRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$request->request("password") || !$request->request("username")) {
|
||||
$response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) {
|
||||
$response->setError(401, 'invalid_grant', 'Invalid username and password combination');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$userInfo = $this->storage->getUserDetails($request->request("username"));
|
||||
|
||||
if (empty($userInfo)) {
|
||||
$response->setError(400, 'invalid_grant', 'Unable to retrieve user information');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($userInfo['user_id'])) {
|
||||
throw new \LogicException("you must set the user_id on the array returned by getUserDetails");
|
||||
}
|
||||
|
||||
$this->userInfo = $userInfo;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientId()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->userInfo['user_id'];
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null;
|
||||
}
|
||||
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
return $accessToken->createAccessToken($client_id, $user_id, $scope);
|
||||
}
|
||||
}
|
106
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php
vendored
Normal file
106
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeController.php
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Controller;
|
||||
|
||||
use OAuth2\Controller\AuthorizeController as BaseAuthorizeController;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @see OAuth2\Controller\AuthorizeControllerInterface
|
||||
*/
|
||||
class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface
|
||||
{
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate an id token if needed.
|
||||
if ($this->needsIdToken($this->getScope()) && $this->getResponseType() == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
|
||||
$params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->getClientId(), $user_id, $this->nonce);
|
||||
}
|
||||
|
||||
// add the nonce to return with the redirect URI
|
||||
$params['nonce'] = $this->nonce;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!parent::validateAuthorizeRequest($request, $response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$nonce = $request->query('nonce');
|
||||
|
||||
// Validate required nonce for "id_token" and "id_token token"
|
||||
if (!$nonce && in_array($this->getResponseType(), array(self::RESPONSE_TYPE_ID_TOKEN, self::RESPONSE_TYPE_ID_TOKEN_TOKEN))) {
|
||||
$response->setError(400, 'invalid_nonce', 'This application requires you specify a nonce parameter');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->nonce = $nonce;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getValidResponseTypes()
|
||||
{
|
||||
return array(
|
||||
self::RESPONSE_TYPE_ACCESS_TOKEN,
|
||||
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
|
||||
self::RESPONSE_TYPE_ID_TOKEN,
|
||||
self::RESPONSE_TYPE_ID_TOKEN_TOKEN,
|
||||
self::RESPONSE_TYPE_CODE_ID_TOKEN,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current request needs to generate an id token.
|
||||
*
|
||||
* ID Tokens are a part of the OpenID Connect specification, so this
|
||||
* method checks whether OpenID Connect is enabled in the server settings
|
||||
* and whether the openid scope was requested.
|
||||
*
|
||||
* @param $request_scope
|
||||
* A space-separated string of scopes.
|
||||
*
|
||||
* @return
|
||||
* TRUE if an id token is needed, FALSE otherwise.
|
||||
*/
|
||||
public function needsIdToken($request_scope)
|
||||
{
|
||||
// see if the "openid" scope exists in the requested scope
|
||||
return $this->scopeUtil->checkScope('openid', $request_scope);
|
||||
}
|
||||
|
||||
public function getNonce()
|
||||
{
|
||||
return $this->nonce;
|
||||
}
|
||||
}
|
10
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
vendored
Normal file
10
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Controller;
|
||||
|
||||
interface AuthorizeControllerInterface
|
||||
{
|
||||
const RESPONSE_TYPE_ID_TOKEN = 'id_token';
|
||||
const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
|
||||
const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
|
||||
}
|
58
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php
vendored
Normal file
58
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoController.php
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Controller;
|
||||
|
||||
use OAuth2\Scope;
|
||||
use OAuth2\TokenType\TokenTypeInterface;
|
||||
use OAuth2\Storage\AccessTokenInterface;
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
use OAuth2\Controller\ResourceController;
|
||||
use OAuth2\ScopeInterface;
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @see OAuth2\Controller\UserInfoControllerInterface
|
||||
*/
|
||||
class UserInfoController extends ResourceController implements UserInfoControllerInterface
|
||||
{
|
||||
private $token;
|
||||
|
||||
protected $tokenType;
|
||||
protected $tokenStorage;
|
||||
protected $userClaimsStorage;
|
||||
protected $config;
|
||||
protected $scopeUtil;
|
||||
|
||||
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
|
||||
{
|
||||
$this->tokenType = $tokenType;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->userClaimsStorage = $userClaimsStorage;
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'www_realm' => 'Service',
|
||||
), $config);
|
||||
|
||||
if (is_null($scopeUtil)) {
|
||||
$scopeUtil = new Scope();
|
||||
}
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
}
|
||||
|
||||
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (!$this->verifyResourceRequest($request, $response, 'openid')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $this->getToken();
|
||||
$claims = $this->userClaimsStorage->getUserClaims($token['user_id'], $token['scope']);
|
||||
// The sub Claim MUST always be returned in the UserInfo Response.
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
$claims += array(
|
||||
'sub' => $token['user_id'],
|
||||
);
|
||||
$response->addParameters($claims);
|
||||
}
|
||||
}
|
23
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
vendored
Normal file
23
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Controller;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This controller is called when the user claims for OpenID Connect's
|
||||
* UserInfo endpoint should be returned.
|
||||
*
|
||||
* ex:
|
||||
* > $response = new OAuth2\Response();
|
||||
* > $userInfoController->handleUserInfoRequest(
|
||||
* > OAuth2\Request::createFromGlobals(),
|
||||
* > $response;
|
||||
* > $response->send();
|
||||
*
|
||||
*/
|
||||
interface UserInfoControllerInterface
|
||||
{
|
||||
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response);
|
||||
}
|
33
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
vendored
Normal file
33
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\GrantType;
|
||||
|
||||
use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class AuthorizationCode extends BaseAuthorizationCode
|
||||
{
|
||||
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
|
||||
{
|
||||
$includeRefreshToken = true;
|
||||
if (isset($this->authCode['id_token'])) {
|
||||
// OpenID Connect requests include the refresh token only if the
|
||||
// offline_access scope has been requested and granted.
|
||||
$scopes = explode(' ', trim($scope));
|
||||
$includeRefreshToken = in_array('offline_access', $scopes);
|
||||
}
|
||||
|
||||
$token = $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
|
||||
if (isset($this->authCode['id_token'])) {
|
||||
$token['id_token'] = $this->authCode['id_token'];
|
||||
}
|
||||
|
||||
$this->storage->expireAuthorizationCode($this->authCode['code']);
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
60
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
vendored
Normal file
60
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface
|
||||
{
|
||||
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
|
||||
{
|
||||
parent::__construct($storage, $config);
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $user_id = null)
|
||||
{
|
||||
// build the URL to redirect to
|
||||
$result = array('query' => array());
|
||||
|
||||
$params += array('scope' => null, 'state' => null, 'id_token' => null);
|
||||
|
||||
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']);
|
||||
|
||||
if (isset($params['state'])) {
|
||||
$result['query']['state'] = $params['state'];
|
||||
}
|
||||
|
||||
return array($params['redirect_uri'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the creation of the authorization code.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier related to the authorization code
|
||||
* @param $user_id
|
||||
* User ID associated with the authorization code
|
||||
* @param $redirect_uri
|
||||
* An absolute URI to which the authorization server will redirect the
|
||||
* user-agent to when the end-user authorization step is completed.
|
||||
* @param $scope
|
||||
* (optional) Scopes to be stored in space-separated string.
|
||||
* @param $id_token
|
||||
* (optional) The OpenID Connect id_token.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null)
|
||||
{
|
||||
$code = $this->generateAuthorizationCode();
|
||||
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token);
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
|
||||
{
|
||||
/**
|
||||
* Handle the creation of the authorization code.
|
||||
*
|
||||
* @param $client_id Client identifier related to the authorization code
|
||||
* @param $user_id User ID associated with the authorization code
|
||||
* @param $redirect_uri An absolute URI to which the authorization server will redirect the
|
||||
* user-agent to when the end-user authorization step is completed.
|
||||
* @param $scope OPTIONAL Scopes to be stored in space-separated string.
|
||||
* @param $id_token OPTIONAL The OpenID Connect id_token.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null);
|
||||
}
|
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
vendored
Normal file
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
class CodeIdToken implements CodeIdTokenInterface
|
||||
{
|
||||
protected $authCode;
|
||||
protected $idToken;
|
||||
|
||||
public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
|
||||
{
|
||||
$this->authCode = $authCode;
|
||||
$this->idToken = $idToken;
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $user_id = null)
|
||||
{
|
||||
$result = $this->authCode->getAuthorizeResponse($params, $user_id);
|
||||
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce']);
|
||||
$result[1]['query']['id_token'] = $id_token;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
vendored
Normal file
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||
|
||||
interface CodeIdTokenInterface extends ResponseTypeInterface
|
||||
{
|
||||
}
|
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php
vendored
Normal file
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdToken.php
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\Encryption\EncryptionInterface;
|
||||
use OAuth2\Encryption\Jwt;
|
||||
use OAuth2\Storage\PublicKeyInterface;
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
|
||||
class IdToken implements IdTokenInterface
|
||||
{
|
||||
protected $userClaimsStorage;
|
||||
protected $publicKeyStorage;
|
||||
protected $config;
|
||||
protected $encryptionUtil;
|
||||
|
||||
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
|
||||
{
|
||||
$this->userClaimsStorage = $userClaimsStorage;
|
||||
$this->publicKeyStorage = $publicKeyStorage;
|
||||
if (is_null($encryptionUtil)) {
|
||||
$encryptionUtil = new Jwt();
|
||||
}
|
||||
$this->encryptionUtil = $encryptionUtil;
|
||||
|
||||
if (!isset($config['issuer'])) {
|
||||
throw new \LogicException('config parameter "issuer" must be set');
|
||||
}
|
||||
$this->config = array_merge(array(
|
||||
'id_lifetime' => 3600,
|
||||
), $config);
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $userInfo = null)
|
||||
{
|
||||
// build the URL to redirect to
|
||||
$result = array('query' => array());
|
||||
$params += array('scope' => null, 'state' => null, 'nonce' => null);
|
||||
|
||||
// create the id token.
|
||||
list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
|
||||
$userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']);
|
||||
|
||||
$id_token = $this->createIdToken($params['client_id'], $userInfo, $params['nonce'], $userClaims, null);
|
||||
$result["fragment"] = array('id_token' => $id_token);
|
||||
if (isset($params['state'])) {
|
||||
$result["fragment"]["state"] = $params['state'];
|
||||
}
|
||||
|
||||
return array($params['redirect_uri'], $result);
|
||||
}
|
||||
|
||||
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null)
|
||||
{
|
||||
// pull auth_time from user info if supplied
|
||||
list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
|
||||
|
||||
$token = array(
|
||||
'iss' => $this->config['issuer'],
|
||||
'sub' => $user_id,
|
||||
'aud' => $client_id,
|
||||
'iat' => time(),
|
||||
'exp' => time() + $this->config['id_lifetime'],
|
||||
'auth_time' => $auth_time,
|
||||
);
|
||||
|
||||
if ($nonce) {
|
||||
$token['nonce'] = $nonce;
|
||||
}
|
||||
|
||||
if ($userClaims) {
|
||||
$token += $userClaims;
|
||||
}
|
||||
|
||||
if ($access_token) {
|
||||
$token['at_hash'] = $this->createAtHash($access_token, $client_id);
|
||||
}
|
||||
|
||||
return $this->encodeToken($token, $client_id);
|
||||
}
|
||||
|
||||
protected function createAtHash($access_token, $client_id = null)
|
||||
{
|
||||
// maps HS256 and RS256 to sha256, etc.
|
||||
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||
$hash_algorithm = 'sha' . substr($algorithm, 2);
|
||||
$hash = hash($hash_algorithm, $access_token);
|
||||
$at_hash = substr($hash, 0, strlen($hash) / 2);
|
||||
|
||||
return $this->encryptionUtil->urlSafeB64Encode($at_hash);
|
||||
}
|
||||
|
||||
protected function encodeToken(array $token, $client_id = null)
|
||||
{
|
||||
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
|
||||
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||
|
||||
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
|
||||
}
|
||||
|
||||
private function getUserIdAndAuthTime($userInfo)
|
||||
{
|
||||
$auth_time = null;
|
||||
|
||||
// support an array for user_id / auth_time
|
||||
if (is_array($userInfo)) {
|
||||
if (!isset($userInfo['user_id'])) {
|
||||
throw new \LogicException('if $user_id argument is an array, user_id index must be set');
|
||||
}
|
||||
|
||||
$auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null;
|
||||
$user_id = $userInfo['user_id'];
|
||||
} else {
|
||||
$user_id = $userInfo;
|
||||
}
|
||||
|
||||
if (is_null($auth_time)) {
|
||||
$auth_time = time();
|
||||
}
|
||||
|
||||
// userInfo is a scalar, and so this is the $user_id. Auth Time is null
|
||||
return array($user_id, $auth_time);
|
||||
}
|
||||
}
|
29
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
vendored
Normal file
29
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||
|
||||
interface IdTokenInterface extends ResponseTypeInterface
|
||||
{
|
||||
/**
|
||||
* Create the id token.
|
||||
*
|
||||
* If Authorization Code Flow is used, the id_token is generated when the
|
||||
* authorization code is issued, and later returned from the token endpoint
|
||||
* together with the access_token.
|
||||
* 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 $access_token OPTIONAL The access token, if known.
|
||||
*
|
||||
* @return string The ID Token represented as a JSON Web Token (JWT).
|
||||
*
|
||||
* @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
*/
|
||||
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null);
|
||||
}
|
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
vendored
Normal file
27
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\AccessTokenInterface;
|
||||
|
||||
class IdTokenToken implements IdTokenTokenInterface
|
||||
{
|
||||
protected $accessToken;
|
||||
protected $idToken;
|
||||
|
||||
public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
$this->idToken = $idToken;
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $user_id = null)
|
||||
{
|
||||
$result = $this->accessToken->getAuthorizeResponse($params, $user_id);
|
||||
$access_token = $result[1]['fragment']['access_token'];
|
||||
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token);
|
||||
$result[1]['fragment']['id_token'] = $id_token;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
vendored
Normal file
9
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\ResponseType;
|
||||
|
||||
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||
|
||||
interface IdTokenTokenInterface extends ResponseTypeInterface
|
||||
{
|
||||
}
|
37
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
vendored
Normal file
37
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Storage;
|
||||
|
||||
use OAuth2\Storage\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get/save authorization codes for the "Authorization Code"
|
||||
* grant type
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
|
||||
{
|
||||
/**
|
||||
* Take the provided authorization code values and store them somewhere.
|
||||
*
|
||||
* This function should be the storage counterpart to getAuthCode().
|
||||
*
|
||||
* If storage fails for some reason, we're not currently checking for
|
||||
* any sort of success/failure, so you should bail out of the script
|
||||
* and provide a descriptive fail message.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
|
||||
*
|
||||
* @param $code authorization code to be stored.
|
||||
* @param $client_id client identifier to be stored.
|
||||
* @param $user_id user identifier to be stored.
|
||||
* @param string $redirect_uri redirect URI(s) to be stored in a space-separated string.
|
||||
* @param int $expires expiration to be stored as a Unix timestamp.
|
||||
* @param string $scope OPTIONAL scopes to be stored in space-separated string.
|
||||
* @param string $id_token OPTIONAL the OpenID Connect id_token.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null);
|
||||
}
|
38
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
vendored
Normal file
38
vendor/bshaffer/oauth2-server-php/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\OpenID\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should retrieve user claims for the OpenID Connect id_token.
|
||||
*/
|
||||
interface UserClaimsInterface
|
||||
{
|
||||
// valid scope values to pass into the user claims API call
|
||||
const VALID_CLAIMS = 'profile email address phone';
|
||||
|
||||
// fields returned for the claims above
|
||||
const PROFILE_CLAIM_VALUES = 'name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at';
|
||||
const EMAIL_CLAIM_VALUES = 'email email_verified';
|
||||
const ADDRESS_CLAIM_VALUES = 'formatted street_address locality region postal_code country';
|
||||
const PHONE_CLAIM_VALUES = 'phone_number phone_number_verified';
|
||||
|
||||
/**
|
||||
* Return claims about the provided user id.
|
||||
*
|
||||
* Groups of claims are returned based on the requested scopes. No group
|
||||
* is required, and no claim is required.
|
||||
*
|
||||
* @param $user_id
|
||||
* The id of the user for which claims should be returned.
|
||||
* @param $scope
|
||||
* The requested scope.
|
||||
* Scopes with matching claims: profile, email, address, phone.
|
||||
*
|
||||
* @return
|
||||
* An array in the claim => value format.
|
||||
*
|
||||
* @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
||||
*/
|
||||
public function getUserClaims($user_id, $scope);
|
||||
}
|
213
vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php
vendored
Normal file
213
vendor/bshaffer/oauth2-server-php/src/OAuth2/Request.php
vendored
Normal file
|
@ -0,0 +1,213 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
/**
|
||||
* OAuth2\Request
|
||||
* This class is taken from the Symfony2 Framework and is part of the Symfony package.
|
||||
* See Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
|
||||
*/
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
public $attributes;
|
||||
public $request;
|
||||
public $query;
|
||||
public $server;
|
||||
public $files;
|
||||
public $cookies;
|
||||
public $headers;
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $query The GET parameters
|
||||
* @param array $request The POST parameters
|
||||
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
|
||||
* @param array $cookies The COOKIE parameters
|
||||
* @param array $files The FILES parameters
|
||||
* @param array $server The SERVER parameters
|
||||
* @param string $content The raw body data
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
|
||||
{
|
||||
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters for this request.
|
||||
*
|
||||
* This method also re-initializes all properties.
|
||||
*
|
||||
* @param array $query The GET parameters
|
||||
* @param array $request The POST parameters
|
||||
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
|
||||
* @param array $cookies The COOKIE parameters
|
||||
* @param array $files The FILES parameters
|
||||
* @param array $server The SERVER parameters
|
||||
* @param string $content The raw body data
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->query = $query;
|
||||
$this->attributes = $attributes;
|
||||
$this->cookies = $cookies;
|
||||
$this->files = $files;
|
||||
$this->server = $server;
|
||||
$this->content = $content;
|
||||
$this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers;
|
||||
}
|
||||
|
||||
public function query($name, $default = null)
|
||||
{
|
||||
return isset($this->query[$name]) ? $this->query[$name] : $default;
|
||||
}
|
||||
|
||||
public function request($name, $default = null)
|
||||
{
|
||||
return isset($this->request[$name]) ? $this->request[$name] : $default;
|
||||
}
|
||||
|
||||
public function server($name, $default = null)
|
||||
{
|
||||
return isset($this->server[$name]) ? $this->server[$name] : $default;
|
||||
}
|
||||
|
||||
public function headers($name, $default = null)
|
||||
{
|
||||
$headers = array_change_key_case($this->headers);
|
||||
$name = strtolower($name);
|
||||
|
||||
return isset($headers[$name]) ? $headers[$name] : $default;
|
||||
}
|
||||
|
||||
public function getAllQueryParameters()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request body content.
|
||||
*
|
||||
* @param Boolean $asResource If true, a resource will be returned
|
||||
*
|
||||
* @return string|resource The request body content or a resource to read the body stream.
|
||||
*/
|
||||
public function getContent($asResource = false)
|
||||
{
|
||||
if (false === $this->content || (true === $asResource && null !== $this->content)) {
|
||||
throw new \LogicException('getContent() can only be called once when using the resource return type.');
|
||||
}
|
||||
|
||||
if (true === $asResource) {
|
||||
$this->content = false;
|
||||
|
||||
return fopen('php://input', 'rb');
|
||||
}
|
||||
|
||||
if (null === $this->content) {
|
||||
$this->content = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
private function getHeadersFromServer($server)
|
||||
{
|
||||
$headers = array();
|
||||
foreach ($server as $key => $value) {
|
||||
if (0 === strpos($key, 'HTTP_')) {
|
||||
$headers[substr($key, 5)] = $value;
|
||||
}
|
||||
// CONTENT_* are not prefixed with HTTP_
|
||||
elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) {
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($server['PHP_AUTH_USER'])) {
|
||||
$headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER'];
|
||||
$headers['PHP_AUTH_PW'] = isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : '';
|
||||
} else {
|
||||
/*
|
||||
* php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
|
||||
* For this workaround to work, add this line to your .htaccess file:
|
||||
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
*
|
||||
* A sample .htaccess file:
|
||||
* RewriteEngine On
|
||||
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
* RewriteCond %{REQUEST_FILENAME} !-f
|
||||
* RewriteRule ^(.*)$ app.php [QSA,L]
|
||||
*/
|
||||
|
||||
$authorizationHeader = null;
|
||||
if (isset($server['HTTP_AUTHORIZATION'])) {
|
||||
$authorizationHeader = $server['HTTP_AUTHORIZATION'];
|
||||
} elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
$authorizationHeader = $server['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$requestHeaders = (array) apache_request_headers();
|
||||
|
||||
// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
|
||||
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
|
||||
|
||||
if (isset($requestHeaders['Authorization'])) {
|
||||
$authorizationHeader = trim($requestHeaders['Authorization']);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $authorizationHeader) {
|
||||
$headers['AUTHORIZATION'] = $authorizationHeader;
|
||||
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
|
||||
if (0 === stripos($authorizationHeader, 'basic')) {
|
||||
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)));
|
||||
if (count($exploded) == 2) {
|
||||
list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PHP_AUTH_USER/PHP_AUTH_PW
|
||||
if (isset($headers['PHP_AUTH_USER'])) {
|
||||
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new request with values from PHP's super globals.
|
||||
*
|
||||
* @return Request A new request
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function createFromGlobals()
|
||||
{
|
||||
$class = get_called_class();
|
||||
$request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
|
||||
|
||||
$contentType = $request->server('CONTENT_TYPE', '');
|
||||
$requestMethod = $request->server('REQUEST_METHOD', 'GET');
|
||||
if (0 === strpos($contentType, 'application/x-www-form-urlencoded')
|
||||
&& in_array(strtoupper($requestMethod), array('PUT', 'DELETE'))
|
||||
) {
|
||||
parse_str($request->getContent(), $data);
|
||||
$request->request = $data;
|
||||
} elseif (0 === strpos($contentType, 'application/json')
|
||||
&& in_array(strtoupper($requestMethod), array('POST', 'PUT', 'DELETE'))
|
||||
) {
|
||||
$data = json_decode($request->getContent(), true);
|
||||
$request->request = $data;
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
}
|
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php
vendored
Normal file
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/RequestInterface.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
interface RequestInterface
|
||||
{
|
||||
public function query($name, $default = null);
|
||||
|
||||
public function request($name, $default = null);
|
||||
|
||||
public function server($name, $default = null);
|
||||
|
||||
public function headers($name, $default = null);
|
||||
|
||||
public function getAllQueryParameters();
|
||||
}
|
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php
vendored
Normal file
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Response.php
vendored
Normal file
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
/**
|
||||
* Class to handle OAuth2 Responses in a graceful way. Use this interface
|
||||
* to output the proper OAuth2 responses.
|
||||
*
|
||||
* @see OAuth2\ResponseInterface
|
||||
*
|
||||
* This class borrows heavily from the Symfony2 Framework and is part of the symfony package
|
||||
* @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
|
||||
*/
|
||||
class Response implements ResponseInterface
|
||||
{
|
||||
public $version;
|
||||
protected $statusCode = 200;
|
||||
protected $statusText;
|
||||
protected $parameters = array();
|
||||
protected $httpHeaders = array();
|
||||
|
||||
public static $statusTexts = array(
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported',
|
||||
);
|
||||
|
||||
public function __construct($parameters = array(), $statusCode = 200, $headers = array())
|
||||
{
|
||||
$this->setParameters($parameters);
|
||||
$this->setStatusCode($statusCode);
|
||||
$this->setHttpHeaders($headers);
|
||||
$this->version = '1.1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the response object to string containing all headers and the response content.
|
||||
*
|
||||
* @return string The response with headers and content
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$headers = array();
|
||||
foreach ($this->httpHeaders as $name => $value) {
|
||||
$headers[$name] = (array) $value;
|
||||
}
|
||||
|
||||
return
|
||||
sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
|
||||
$this->getHttpHeadersAsString($headers)."\r\n".
|
||||
$this->getResponseBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the build header line.
|
||||
*
|
||||
* @param string $name The header name
|
||||
* @param string $value The header value
|
||||
*
|
||||
* @return string The built header line
|
||||
*/
|
||||
protected function buildHeader($name, $value)
|
||||
{
|
||||
return sprintf("%s: %s\n", $name, $value);
|
||||
}
|
||||
|
||||
public function getStatusCode()
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
public function setStatusCode($statusCode, $text = null)
|
||||
{
|
||||
$this->statusCode = (int) $statusCode;
|
||||
if ($this->isInvalid()) {
|
||||
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
|
||||
}
|
||||
|
||||
$this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
|
||||
}
|
||||
|
||||
public function getStatusText()
|
||||
{
|
||||
return $this->statusText;
|
||||
}
|
||||
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function setParameters(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
public function addParameters(array $parameters)
|
||||
{
|
||||
$this->parameters = array_merge($this->parameters, $parameters);
|
||||
}
|
||||
|
||||
public function getParameter($name, $default = null)
|
||||
{
|
||||
return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
|
||||
}
|
||||
|
||||
public function setParameter($name, $value)
|
||||
{
|
||||
$this->parameters[$name] = $value;
|
||||
}
|
||||
|
||||
public function setHttpHeaders(array $httpHeaders)
|
||||
{
|
||||
$this->httpHeaders = $httpHeaders;
|
||||
}
|
||||
|
||||
public function setHttpHeader($name, $value)
|
||||
{
|
||||
$this->httpHeaders[$name] = $value;
|
||||
}
|
||||
|
||||
public function addHttpHeaders(array $httpHeaders)
|
||||
{
|
||||
$this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
|
||||
}
|
||||
|
||||
public function getHttpHeaders()
|
||||
{
|
||||
return $this->httpHeaders;
|
||||
}
|
||||
|
||||
public function getHttpHeader($name, $default = null)
|
||||
{
|
||||
return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
|
||||
}
|
||||
|
||||
public function getResponseBody($format = 'json')
|
||||
{
|
||||
switch ($format) {
|
||||
case 'json':
|
||||
return json_encode($this->parameters);
|
||||
case 'xml':
|
||||
// this only works for single-level arrays
|
||||
$xml = new \SimpleXMLElement('<response/>');
|
||||
foreach ($this->parameters as $key => $param) {
|
||||
$xml->addChild($key, $param);
|
||||
}
|
||||
|
||||
return $xml->asXML();
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
|
||||
|
||||
}
|
||||
|
||||
public function send($format = 'json')
|
||||
{
|
||||
// headers have already been sent by the developer
|
||||
if (headers_sent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($format) {
|
||||
case 'json':
|
||||
$this->setHttpHeader('Content-Type', 'application/json');
|
||||
break;
|
||||
case 'xml':
|
||||
$this->setHttpHeader('Content-Type', 'text/xml');
|
||||
break;
|
||||
}
|
||||
// status
|
||||
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
|
||||
|
||||
foreach ($this->getHttpHeaders() as $name => $header) {
|
||||
header(sprintf('%s: %s', $name, $header));
|
||||
}
|
||||
echo $this->getResponseBody($format);
|
||||
}
|
||||
|
||||
public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
|
||||
{
|
||||
$parameters = array(
|
||||
'error' => $error,
|
||||
'error_description' => $errorDescription,
|
||||
);
|
||||
|
||||
if (!is_null($errorUri)) {
|
||||
if (strlen($errorUri) > 0 && $errorUri[0] == '#') {
|
||||
// we are referencing an oauth bookmark (for brevity)
|
||||
$errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri;
|
||||
}
|
||||
$parameters['error_uri'] = $errorUri;
|
||||
}
|
||||
|
||||
$httpHeaders = array(
|
||||
'Cache-Control' => 'no-store'
|
||||
);
|
||||
|
||||
$this->setStatusCode($statusCode);
|
||||
$this->addParameters($parameters);
|
||||
$this->addHttpHeaders($httpHeaders);
|
||||
|
||||
if (!$this->isClientError() && !$this->isServerError()) {
|
||||
throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
|
||||
}
|
||||
}
|
||||
|
||||
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
|
||||
{
|
||||
if (empty($url)) {
|
||||
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
|
||||
}
|
||||
|
||||
$parameters = array();
|
||||
|
||||
if (!is_null($state)) {
|
||||
$parameters['state'] = $state;
|
||||
}
|
||||
|
||||
if (!is_null($error)) {
|
||||
$this->setError(400, $error, $errorDescription, $errorUri);
|
||||
}
|
||||
$this->setStatusCode($statusCode);
|
||||
$this->addParameters($parameters);
|
||||
|
||||
if (count($this->parameters) > 0) {
|
||||
// add parameters to URL redirection
|
||||
$parts = parse_url($url);
|
||||
$sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?';
|
||||
$url .= $sep . http_build_query($this->parameters);
|
||||
}
|
||||
|
||||
$this->addHttpHeaders(array('Location' => $url));
|
||||
|
||||
if (!$this->isRedirection()) {
|
||||
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isInvalid()
|
||||
{
|
||||
return $this->statusCode < 100 || $this->statusCode >= 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isInformational()
|
||||
{
|
||||
return $this->statusCode >= 100 && $this->statusCode < 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isSuccessful()
|
||||
{
|
||||
return $this->statusCode >= 200 && $this->statusCode < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isRedirection()
|
||||
{
|
||||
return $this->statusCode >= 300 && $this->statusCode < 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isClientError()
|
||||
{
|
||||
return $this->statusCode >= 400 && $this->statusCode < 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isServerError()
|
||||
{
|
||||
return $this->statusCode >= 500 && $this->statusCode < 600;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions from Symfony2 HttpFoundation - output pretty header
|
||||
*/
|
||||
private function getHttpHeadersAsString($headers)
|
||||
{
|
||||
if (count($headers) == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$max = max(array_map('strlen', array_keys($headers))) + 1;
|
||||
$content = '';
|
||||
ksort($headers);
|
||||
foreach ($headers as $name => $values) {
|
||||
foreach ($values as $value) {
|
||||
$content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function beautifyHeaderName($name)
|
||||
{
|
||||
return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
|
||||
}
|
||||
|
||||
private function beautifyCallback($match)
|
||||
{
|
||||
return '-'.strtoupper($match[1]);
|
||||
}
|
||||
}
|
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php
vendored
Normal file
24
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseInterface.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
/**
|
||||
* Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses
|
||||
* for errors and successes
|
||||
*
|
||||
* @see OAuth2\Response
|
||||
*/
|
||||
interface ResponseInterface
|
||||
{
|
||||
public function addParameters(array $parameters);
|
||||
|
||||
public function addHttpHeaders(array $httpHeaders);
|
||||
|
||||
public function setStatusCode($statusCode);
|
||||
|
||||
public function setError($statusCode, $name, $description = null, $uri = null);
|
||||
|
||||
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
|
||||
|
||||
public function getParameter($name);
|
||||
}
|
194
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php
vendored
Normal file
194
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessToken.php
vendored
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
|
||||
use OAuth2\Storage\RefreshTokenInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class AccessToken implements AccessTokenInterface
|
||||
{
|
||||
protected $tokenStorage;
|
||||
protected $refreshStorage;
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information
|
||||
* @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information
|
||||
* @param array $config OPTIONAL Configuration options for the server
|
||||
* <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())
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->refreshStorage = $refreshStorage;
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'token_type' => 'bearer',
|
||||
'access_lifetime' => 3600,
|
||||
'refresh_token_lifetime' => 1209600,
|
||||
), $config);
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $user_id = null)
|
||||
{
|
||||
// build the URL to redirect to
|
||||
$result = array('query' => array());
|
||||
|
||||
$params += array('scope' => null, 'state' => null);
|
||||
|
||||
/*
|
||||
* a refresh token MUST NOT be included in the fragment
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.2.2
|
||||
*/
|
||||
$includeRefreshToken = false;
|
||||
$result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken);
|
||||
|
||||
if (isset($params['state'])) {
|
||||
$result["fragment"]["state"] = $params['state'];
|
||||
}
|
||||
|
||||
return array($params['redirect_uri'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||
*
|
||||
* @param $client_id client identifier related to the access token.
|
||||
* @param $user_id user ID associated with the access token
|
||||
* @param $scope OPTIONAL scopes to be stored in space-separated string.
|
||||
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||
* @ingroup oauth2_section_5
|
||||
*/
|
||||
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
|
||||
{
|
||||
$token = array(
|
||||
"access_token" => $this->generateAccessToken(),
|
||||
"expires_in" => $this->config['access_lifetime'],
|
||||
"token_type" => $this->config['token_type'],
|
||||
"scope" => $scope
|
||||
);
|
||||
|
||||
$this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
|
||||
|
||||
/*
|
||||
* Issue a refresh token also, if we support them
|
||||
*
|
||||
* Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
|
||||
* is supplied in the constructor
|
||||
*/
|
||||
if ($includeRefreshToken && $this->refreshStorage) {
|
||||
$token["refresh_token"] = $this->generateRefreshToken();
|
||||
$expires = 0;
|
||||
if ($this->config['refresh_token_lifetime'] > 0) {
|
||||
$expires = time() + $this->config['refresh_token_lifetime'];
|
||||
}
|
||||
$this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an unique access token.
|
||||
*
|
||||
* Implementing classes may want to override this function to implement
|
||||
* other access token generation schemes.
|
||||
*
|
||||
* @return
|
||||
* An unique access token.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
protected function generateAccessToken()
|
||||
{
|
||||
if (function_exists('mcrypt_create_iv')) {
|
||||
$randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM);
|
||||
if ($randomData !== false && strlen($randomData) === 20) {
|
||||
return bin2hex($randomData);
|
||||
}
|
||||
}
|
||||
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$randomData = openssl_random_pseudo_bytes(20);
|
||||
if ($randomData !== false && strlen($randomData) === 20) {
|
||||
return bin2hex($randomData);
|
||||
}
|
||||
}
|
||||
if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
|
||||
$randomData = file_get_contents('/dev/urandom', false, null, 0, 20);
|
||||
if ($randomData !== false && strlen($randomData) === 20) {
|
||||
return bin2hex($randomData);
|
||||
}
|
||||
}
|
||||
// Last resort which you probably should just get rid of:
|
||||
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
|
||||
|
||||
return substr(hash('sha512', $randomData), 0, 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an unique refresh token
|
||||
*
|
||||
* Implementing classes may want to override this function to implement
|
||||
* other refresh token generation schemes.
|
||||
*
|
||||
* @return
|
||||
* An unique refresh.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
* @see OAuth2::generateAccessToken()
|
||||
*/
|
||||
protected function generateRefreshToken()
|
||||
{
|
||||
return $this->generateAccessToken(); // let's reuse the same scheme for token generation
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the revoking of refresh tokens, and access tokens if supported / desirable
|
||||
* RFC7009 specifies that "If the server is unable to locate the token using
|
||||
* the given hint, it MUST extend its search across all of its supported token types"
|
||||
*
|
||||
* @param $token
|
||||
* @param null $tokenTypeHint
|
||||
* @return boolean
|
||||
*/
|
||||
public function revokeToken($token, $tokenTypeHint = null)
|
||||
{
|
||||
if ($tokenTypeHint == 'refresh_token') {
|
||||
if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @TODO remove in v2 */
|
||||
if (!method_exists($this->tokenStorage, 'unsetAccessToken')) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage)
|
||||
));
|
||||
}
|
||||
|
||||
$revoked = $this->tokenStorage->unsetAccessToken($token);
|
||||
|
||||
// if a typehint is supplied and fails, try other storages
|
||||
// @see https://tools.ietf.org/html/rfc7009#section-2.1
|
||||
if (!$revoked && $tokenTypeHint != 'refresh_token') {
|
||||
if ($this->refreshStorage) {
|
||||
$revoked = $this->refreshStorage->unsetRefreshToken($token);
|
||||
}
|
||||
}
|
||||
|
||||
return $revoked;
|
||||
}
|
||||
}
|
34
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php
vendored
Normal file
34
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AccessTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AccessTokenInterface extends ResponseTypeInterface
|
||||
{
|
||||
/**
|
||||
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||
*
|
||||
* @param $client_id client identifier related to the access token.
|
||||
* @param $user_id user ID associated with the access token
|
||||
* @param $scope OPTONAL scopes to be stored in space-separated string.
|
||||
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||
* @ingroup oauth2_section_5
|
||||
*/
|
||||
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true);
|
||||
|
||||
/**
|
||||
* Handle the revoking of refresh tokens, and access tokens if supported / desirable
|
||||
*
|
||||
* @param $token
|
||||
* @param $tokenTypeHint
|
||||
* @return mixed
|
||||
*
|
||||
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
|
||||
*/
|
||||
//public function revokeToken($token, $tokenTypeHint);
|
||||
}
|
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php
vendored
Normal file
100
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCode.php
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class AuthorizationCode implements AuthorizationCodeInterface
|
||||
{
|
||||
protected $storage;
|
||||
protected $config;
|
||||
|
||||
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->config = array_merge(array(
|
||||
'enforce_redirect' => false,
|
||||
'auth_code_lifetime' => 30,
|
||||
), $config);
|
||||
}
|
||||
|
||||
public function getAuthorizeResponse($params, $user_id = null)
|
||||
{
|
||||
// build the URL to redirect to
|
||||
$result = array('query' => array());
|
||||
|
||||
$params += array('scope' => null, 'state' => null);
|
||||
|
||||
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']);
|
||||
|
||||
if (isset($params['state'])) {
|
||||
$result['query']['state'] = $params['state'];
|
||||
}
|
||||
|
||||
return array($params['redirect_uri'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the creation of the authorization code.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier related to the authorization code
|
||||
* @param $user_id
|
||||
* User ID associated with the authorization code
|
||||
* @param $redirect_uri
|
||||
* An absolute URI to which the authorization server will redirect the
|
||||
* user-agent to when the end-user authorization step is completed.
|
||||
* @param $scope
|
||||
* (optional) Scopes to be stored in space-separated string.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null)
|
||||
{
|
||||
$code = $this->generateAuthorizationCode();
|
||||
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* TRUE if the grant type requires a redirect_uri, FALSE if not
|
||||
*/
|
||||
public function enforceRedirect()
|
||||
{
|
||||
return $this->config['enforce_redirect'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an unique auth code.
|
||||
*
|
||||
* Implementing classes may want to override this function to implement
|
||||
* other auth code generation schemes.
|
||||
*
|
||||
* @return
|
||||
* An unique auth code.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
protected function generateAuthorizationCode()
|
||||
{
|
||||
$tokenLen = 40;
|
||||
if (function_exists('mcrypt_create_iv')) {
|
||||
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);
|
||||
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||
$randomData = openssl_random_pseudo_bytes(100);
|
||||
} elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
|
||||
$randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
|
||||
} else {
|
||||
$randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
|
||||
}
|
||||
|
||||
return substr(hash('sha512', $randomData), 0, $tokenLen);
|
||||
}
|
||||
}
|
30
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
30
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AuthorizationCodeInterface extends ResponseTypeInterface
|
||||
{
|
||||
/**
|
||||
* @return
|
||||
* TRUE if the grant type requires a redirect_uri, FALSE if not
|
||||
*/
|
||||
public function enforceRedirect();
|
||||
|
||||
/**
|
||||
* Handle the creation of the authorization code.
|
||||
*
|
||||
* @param $client_id client identifier related to the authorization code
|
||||
* @param $user_id user id associated with the authorization code
|
||||
* @param $redirect_uri an absolute URI to which the authorization server will redirect the
|
||||
* user-agent to when the end-user authorization step is completed.
|
||||
* @param $scope OPTIONAL scopes to be stored in space-separated string.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null);
|
||||
}
|
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php
vendored
Normal file
124
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
use OAuth2\Encryption\EncryptionInterface;
|
||||
use OAuth2\Encryption\Jwt;
|
||||
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
|
||||
use OAuth2\Storage\RefreshTokenInterface;
|
||||
use OAuth2\Storage\PublicKeyInterface;
|
||||
use OAuth2\Storage\Memory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class JwtAccessToken extends AccessToken
|
||||
{
|
||||
protected $publicKeyStorage;
|
||||
protected $encryptionUtil;
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* - store_encrypted_token_string (bool true)
|
||||
* whether the entire encrypted string is stored,
|
||||
* or just the token ID is stored
|
||||
*/
|
||||
public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
|
||||
{
|
||||
$this->publicKeyStorage = $publicKeyStorage;
|
||||
$config = array_merge(array(
|
||||
'store_encrypted_token_string' => true,
|
||||
'issuer' => ''
|
||||
), $config);
|
||||
if (is_null($tokenStorage)) {
|
||||
// a pass-thru, so we can call the parent constructor
|
||||
$tokenStorage = new Memory();
|
||||
}
|
||||
if (is_null($encryptionUtil)) {
|
||||
$encryptionUtil = new Jwt();
|
||||
}
|
||||
$this->encryptionUtil = $encryptionUtil;
|
||||
parent::__construct($tokenStorage, $refreshStorage, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the creation of access token, also issue refresh token if supported / desirable.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier related to the access token.
|
||||
* @param $user_id
|
||||
* User ID associated with the access token
|
||||
* @param $scope
|
||||
* (optional) Scopes to be stored in space-separated string.
|
||||
* @param bool $includeRefreshToken
|
||||
* If true, a new refresh_token will be added to the response
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-5
|
||||
* @ingroup oauth2_section_5
|
||||
*/
|
||||
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
|
||||
{
|
||||
// token to encrypt
|
||||
$expires = time() + $this->config['access_lifetime'];
|
||||
$id = $this->generateAccessToken();
|
||||
$jwtAccessToken = array(
|
||||
'id' => $id, // for BC (see #591)
|
||||
'jti' => $id,
|
||||
'iss' => $this->config['issuer'],
|
||||
'aud' => $client_id,
|
||||
'sub' => $user_id,
|
||||
'exp' => $expires,
|
||||
'iat' => time(),
|
||||
'token_type' => $this->config['token_type'],
|
||||
'scope' => $scope
|
||||
);
|
||||
|
||||
/*
|
||||
* Encode the token data into a single access_token string
|
||||
*/
|
||||
$access_token = $this->encodeToken($jwtAccessToken, $client_id);
|
||||
|
||||
/*
|
||||
* Save the token to a secondary storage. This is implemented on the
|
||||
* OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
|
||||
* if no secondary storage has been supplied
|
||||
*/
|
||||
$token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id'];
|
||||
$this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
|
||||
|
||||
// token to return to the client
|
||||
$token = array(
|
||||
'access_token' => $access_token,
|
||||
'expires_in' => $this->config['access_lifetime'],
|
||||
'token_type' => $this->config['token_type'],
|
||||
'scope' => $scope
|
||||
);
|
||||
|
||||
/*
|
||||
* Issue a refresh token also, if we support them
|
||||
*
|
||||
* Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
|
||||
* is supplied in the constructor
|
||||
*/
|
||||
if ($includeRefreshToken && $this->refreshStorage) {
|
||||
$refresh_token = $this->generateRefreshToken();
|
||||
$expires = 0;
|
||||
if ($this->config['refresh_token_lifetime'] > 0) {
|
||||
$expires = time() + $this->config['refresh_token_lifetime'];
|
||||
}
|
||||
$this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
|
||||
$token['refresh_token'] = $refresh_token;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
protected function encodeToken(array $token, $client_id = null)
|
||||
{
|
||||
$private_key = $this->publicKeyStorage->getPrivateKey($client_id);
|
||||
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||
|
||||
return $this->encryptionUtil->encode($token, $private_key, $algorithm);
|
||||
}
|
||||
}
|
8
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php
vendored
Normal file
8
vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/ResponseTypeInterface.php
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\ResponseType;
|
||||
|
||||
interface ResponseTypeInterface
|
||||
{
|
||||
public function getAuthorizeResponse($params, $user_id = null);
|
||||
}
|
103
vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php
vendored
Normal file
103
vendor/bshaffer/oauth2-server-php/src/OAuth2/Scope.php
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
use OAuth2\Storage\Memory;
|
||||
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
|
||||
|
||||
/**
|
||||
* @see OAuth2\ScopeInterface
|
||||
*/
|
||||
class Scope implements ScopeInterface
|
||||
{
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @param mixed @storage
|
||||
* Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
|
||||
*/
|
||||
public function __construct($storage = null)
|
||||
{
|
||||
if (is_null($storage) || is_array($storage)) {
|
||||
$storage = new Memory((array) $storage);
|
||||
}
|
||||
|
||||
if (!$storage instanceof ScopeStorageInterface) {
|
||||
throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
|
||||
}
|
||||
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if everything in required scope is contained in available scope.
|
||||
*
|
||||
* @param $required_scope
|
||||
* A space-separated string of scopes.
|
||||
*
|
||||
* @return
|
||||
* TRUE if everything in required scope is contained in available scope,
|
||||
* and FALSE if it isn't.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-7
|
||||
*
|
||||
* @ingroup oauth2_section_7
|
||||
*/
|
||||
public function checkScope($required_scope, $available_scope)
|
||||
{
|
||||
$required_scope = explode(' ', trim($required_scope));
|
||||
$available_scope = explode(' ', trim($available_scope));
|
||||
|
||||
return (count(array_diff($required_scope, $available_scope)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided scope exists in storage.
|
||||
*
|
||||
* @param $scope
|
||||
* A space-separated string of scopes.
|
||||
*
|
||||
* @return
|
||||
* TRUE if it exists, FALSE otherwise.
|
||||
*/
|
||||
public function scopeExists($scope)
|
||||
{
|
||||
// Check reserved scopes first.
|
||||
$scope = explode(' ', trim($scope));
|
||||
$reservedScope = $this->getReservedScopes();
|
||||
$nonReservedScopes = array_diff($scope, $reservedScope);
|
||||
if (count($nonReservedScopes) == 0) {
|
||||
return true;
|
||||
} else {
|
||||
// Check the storage for non-reserved scopes.
|
||||
$nonReservedScopes = implode(' ', $nonReservedScopes);
|
||||
|
||||
return $this->storage->scopeExists($nonReservedScopes);
|
||||
}
|
||||
}
|
||||
|
||||
public function getScopeFromRequest(RequestInterface $request)
|
||||
{
|
||||
// "scope" is valid if passed in either POST or QUERY
|
||||
return $request->request('scope', $request->query('scope'));
|
||||
}
|
||||
|
||||
public function getDefaultScope($client_id = null)
|
||||
{
|
||||
return $this->storage->getDefaultScope($client_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reserved scopes needed by the server.
|
||||
*
|
||||
* In case OpenID Connect is used, these scopes must include:
|
||||
* 'openid', offline_access'.
|
||||
*
|
||||
* @return
|
||||
* An array of reserved scopes.
|
||||
*/
|
||||
public function getReservedScopes()
|
||||
{
|
||||
return array('openid', 'offline_access');
|
||||
}
|
||||
}
|
40
vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php
vendored
Normal file
40
vendor/bshaffer/oauth2-server-php/src/OAuth2/ScopeInterface.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
|
||||
|
||||
/**
|
||||
* Class to handle scope implementation logic
|
||||
*
|
||||
* @see OAuth2\Storage\ScopeInterface
|
||||
*/
|
||||
interface ScopeInterface extends ScopeStorageInterface
|
||||
{
|
||||
/**
|
||||
* Check if everything in required scope is contained in available scope.
|
||||
*
|
||||
* @param $required_scope
|
||||
* A space-separated string of scopes.
|
||||
*
|
||||
* @return
|
||||
* TRUE if everything in required scope is contained in available scope,
|
||||
* and FALSE if it isn't.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-7
|
||||
*
|
||||
* @ingroup oauth2_section_7
|
||||
*/
|
||||
public function checkScope($required_scope, $available_scope);
|
||||
|
||||
/**
|
||||
* Return scope info from request
|
||||
*
|
||||
* @param OAuth2\RequestInterface
|
||||
* Request object to check
|
||||
*
|
||||
* @return
|
||||
* string representation of requested scope
|
||||
*/
|
||||
public function getScopeFromRequest(RequestInterface $request);
|
||||
}
|
832
vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php
vendored
Normal file
832
vendor/bshaffer/oauth2-server-php/src/OAuth2/Server.php
vendored
Normal file
|
@ -0,0 +1,832 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2;
|
||||
|
||||
use OAuth2\Controller\ResourceControllerInterface;
|
||||
use OAuth2\Controller\ResourceController;
|
||||
use OAuth2\OpenID\Controller\UserInfoControllerInterface;
|
||||
use OAuth2\OpenID\Controller\UserInfoController;
|
||||
use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController;
|
||||
use OAuth2\OpenID\ResponseType\AuthorizationCode as OpenIDAuthorizationCodeResponseType;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
use OAuth2\OpenID\GrantType\AuthorizationCode as OpenIDAuthorizationCodeGrantType;
|
||||
use OAuth2\Controller\AuthorizeControllerInterface;
|
||||
use OAuth2\Controller\AuthorizeController;
|
||||
use OAuth2\Controller\TokenControllerInterface;
|
||||
use OAuth2\Controller\TokenController;
|
||||
use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
|
||||
use OAuth2\ClientAssertionType\HttpBasic;
|
||||
use OAuth2\ResponseType\ResponseTypeInterface;
|
||||
use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType;
|
||||
use OAuth2\ResponseType\AccessToken;
|
||||
use OAuth2\ResponseType\JwtAccessToken;
|
||||
use OAuth2\OpenID\ResponseType\CodeIdToken;
|
||||
use OAuth2\OpenID\ResponseType\IdToken;
|
||||
use OAuth2\OpenID\ResponseType\IdTokenToken;
|
||||
use OAuth2\TokenType\TokenTypeInterface;
|
||||
use OAuth2\TokenType\Bearer;
|
||||
use OAuth2\GrantType\GrantTypeInterface;
|
||||
use OAuth2\GrantType\UserCredentials;
|
||||
use OAuth2\GrantType\ClientCredentials;
|
||||
use OAuth2\GrantType\RefreshToken;
|
||||
use OAuth2\GrantType\AuthorizationCode;
|
||||
use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
|
||||
use OAuth2\Storage\JwtAccessTokenInterface;
|
||||
|
||||
/**
|
||||
* Server class for OAuth2
|
||||
* This class serves as a convience class which wraps the other Controller classes
|
||||
*
|
||||
* @see OAuth2\Controller\ResourceController
|
||||
* @see OAuth2\Controller\AuthorizeController
|
||||
* @see OAuth2\Controller\TokenController
|
||||
*/
|
||||
class Server implements ResourceControllerInterface,
|
||||
AuthorizeControllerInterface,
|
||||
TokenControllerInterface,
|
||||
UserInfoControllerInterface
|
||||
{
|
||||
// misc properties
|
||||
protected $response;
|
||||
protected $config;
|
||||
protected $storages;
|
||||
|
||||
// servers
|
||||
protected $authorizeController;
|
||||
protected $tokenController;
|
||||
protected $resourceController;
|
||||
protected $userInfoController;
|
||||
|
||||
// config classes
|
||||
protected $grantTypes;
|
||||
protected $responseTypes;
|
||||
protected $tokenType;
|
||||
protected $scopeUtil;
|
||||
protected $clientAssertionType;
|
||||
|
||||
protected $storageMap = array(
|
||||
'access_token' => 'OAuth2\Storage\AccessTokenInterface',
|
||||
'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
|
||||
'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface',
|
||||
'client' => 'OAuth2\Storage\ClientInterface',
|
||||
'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface',
|
||||
'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface',
|
||||
'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface',
|
||||
'public_key' => 'OAuth2\Storage\PublicKeyInterface',
|
||||
'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface',
|
||||
'scope' => 'OAuth2\Storage\ScopeInterface',
|
||||
);
|
||||
|
||||
protected $responseTypeMap = array(
|
||||
'token' => 'OAuth2\ResponseType\AccessTokenInterface',
|
||||
'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
|
||||
'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface',
|
||||
'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface',
|
||||
'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface',
|
||||
);
|
||||
|
||||
/**
|
||||
* @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the
|
||||
* required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
|
||||
* @param array $config specify a different token lifetime, token header name, etc
|
||||
* @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
|
||||
* @param array $responseTypes Response types to use. array keys should be "code" and and "token" for
|
||||
* Access Token and Authorization Code response types
|
||||
* @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
|
||||
* @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope
|
||||
* @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
|
||||
*
|
||||
* @ingroup oauth2_section_7
|
||||
*/
|
||||
public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null)
|
||||
{
|
||||
$storage = is_array($storage) ? $storage : array($storage);
|
||||
$this->storages = array();
|
||||
foreach ($storage as $key => $service) {
|
||||
$this->addStorage($service, $key);
|
||||
}
|
||||
|
||||
// merge all config values. These get passed to our controller objects
|
||||
$this->config = array_merge(array(
|
||||
'use_jwt_access_tokens' => false,
|
||||
'store_encrypted_token_string' => true,
|
||||
'use_openid_connect' => false,
|
||||
'id_lifetime' => 3600,
|
||||
'access_lifetime' => 3600,
|
||||
'www_realm' => 'Service',
|
||||
'token_param_name' => 'access_token',
|
||||
'token_bearer_header_name' => 'Bearer',
|
||||
'enforce_state' => true,
|
||||
'require_exact_redirect_uri' => true,
|
||||
'allow_implicit' => false,
|
||||
'allow_credentials_in_request_body' => true,
|
||||
'allow_public_clients' => true,
|
||||
'always_issue_new_refresh_token' => false,
|
||||
'unset_refresh_token_after_use' => true,
|
||||
), $config);
|
||||
|
||||
foreach ($grantTypes as $key => $grantType) {
|
||||
$this->addGrantType($grantType, $key);
|
||||
}
|
||||
|
||||
foreach ($responseTypes as $key => $responseType) {
|
||||
$this->addResponseType($responseType, $key);
|
||||
}
|
||||
|
||||
$this->tokenType = $tokenType;
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
$this->clientAssertionType = $clientAssertionType;
|
||||
|
||||
if ($this->config['use_openid_connect']) {
|
||||
$this->validateOpenIdConnect();
|
||||
}
|
||||
}
|
||||
|
||||
public function getAuthorizeController()
|
||||
{
|
||||
if (is_null($this->authorizeController)) {
|
||||
$this->authorizeController = $this->createDefaultAuthorizeController();
|
||||
}
|
||||
|
||||
return $this->authorizeController;
|
||||
}
|
||||
|
||||
public function getTokenController()
|
||||
{
|
||||
if (is_null($this->tokenController)) {
|
||||
$this->tokenController = $this->createDefaultTokenController();
|
||||
}
|
||||
|
||||
return $this->tokenController;
|
||||
}
|
||||
|
||||
public function getResourceController()
|
||||
{
|
||||
if (is_null($this->resourceController)) {
|
||||
$this->resourceController = $this->createDefaultResourceController();
|
||||
}
|
||||
|
||||
return $this->resourceController;
|
||||
}
|
||||
|
||||
public function getUserInfoController()
|
||||
{
|
||||
if (is_null($this->userInfoController)) {
|
||||
$this->userInfoController = $this->createDefaultUserInfoController();
|
||||
}
|
||||
|
||||
return $this->userInfoController;
|
||||
}
|
||||
|
||||
/**
|
||||
* every getter deserves a setter
|
||||
*/
|
||||
public function setAuthorizeController(AuthorizeControllerInterface $authorizeController)
|
||||
{
|
||||
$this->authorizeController = $authorizeController;
|
||||
}
|
||||
|
||||
/**
|
||||
* every getter deserves a setter
|
||||
*/
|
||||
public function setTokenController(TokenControllerInterface $tokenController)
|
||||
{
|
||||
$this->tokenController = $tokenController;
|
||||
}
|
||||
|
||||
/**
|
||||
* every getter deserves a setter
|
||||
*/
|
||||
public function setResourceController(ResourceControllerInterface $resourceController)
|
||||
{
|
||||
$this->resourceController = $resourceController;
|
||||
}
|
||||
|
||||
/**
|
||||
* every getter deserves a setter
|
||||
*/
|
||||
public function setUserInfoController(UserInfoControllerInterface $userInfoController)
|
||||
{
|
||||
$this->userInfoController = $userInfoController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return claims about the authenticated end-user.
|
||||
* This would be called from the "/UserInfo" endpoint as defined in the spec.
|
||||
*
|
||||
* @param $request - OAuth2\RequestInterface
|
||||
* Request object to grant access token
|
||||
*
|
||||
* @param $response - OAuth2\ResponseInterface
|
||||
* Response object containing error messages (failure) or user claims (success)
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws LogicException
|
||||
*
|
||||
* @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
||||
*/
|
||||
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$this->getUserInfoController()->handleUserInfoRequest($request, $this->response);
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant or deny a requested access token.
|
||||
* This would be called from the "/token" endpoint as defined in the spec.
|
||||
* Obviously, you can call your endpoint whatever you want.
|
||||
*
|
||||
* @param $request - OAuth2\RequestInterface
|
||||
* Request object to grant access token
|
||||
*
|
||||
* @param $response - OAuth2\ResponseInterface
|
||||
* Response object containing error messages (failure) or access token (success)
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws LogicException
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-10.6
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1.3
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$this->getTokenController()->handleTokenRequest($request, $this->response);
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$value = $this->getTokenController()->grantAccessToken($request, $this->response);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a revoke token request
|
||||
* This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7009#section-2
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return Response|ResponseInterface
|
||||
*/
|
||||
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$this->getTokenController()->handleRevokeRequest($request, $this->response);
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect the user appropriately after approval.
|
||||
*
|
||||
* After the user has approved or denied the resource request the
|
||||
* authorization server should call this function to redirect the user
|
||||
* appropriately.
|
||||
*
|
||||
* @param $request
|
||||
* The request should have the follow parameters set in the querystring:
|
||||
* - response_type: The requested response: an access token, an
|
||||
* authorization code, or both.
|
||||
* - client_id: The client identifier as described in Section 2.
|
||||
* - redirect_uri: An absolute URI to which the authorization server
|
||||
* will redirect the user-agent to when the end-user authorization
|
||||
* step is completed.
|
||||
* - scope: (optional) The scope of the resource request expressed as a
|
||||
* list of space-delimited strings.
|
||||
* - state: (optional) An opaque value used by the client to maintain
|
||||
* state between the request and callback.
|
||||
* @param $is_authorized
|
||||
* TRUE or FALSE depending on whether the user authorized the access.
|
||||
* @param $user_id
|
||||
* Identifier of user who authorized the client
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id);
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the authorization request data out of the HTTP request.
|
||||
* - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it
|
||||
* by setting $config['enforce_redirect'] to true.
|
||||
* - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that
|
||||
* CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true.
|
||||
*
|
||||
* The draft specifies that the parameters should be retrieved from GET, override the Response
|
||||
* object to change this
|
||||
*
|
||||
* @return
|
||||
* The authorization parameters so the authorization server can prompt
|
||||
* the user for approval if valid.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-10.12
|
||||
*
|
||||
* @ingroup oauth2_section_3
|
||||
*/
|
||||
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
|
||||
{
|
||||
$this->response = is_null($response) ? new Response() : $response;
|
||||
$value = $this->getResourceController()->getAccessTokenData($request, $this->response);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||
{
|
||||
if (!is_string($identifier)) {
|
||||
$identifier = $grantType->getQuerystringIdentifier();
|
||||
}
|
||||
|
||||
$this->grantTypes[$identifier] = $grantType;
|
||||
|
||||
// persist added grant type down to TokenController
|
||||
if (!is_null($this->tokenController)) {
|
||||
$this->getTokenController()->addGrantType($grantType, $identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a storage object for the server
|
||||
*
|
||||
* @param $storage
|
||||
* An object implementing one of the Storage interfaces
|
||||
* @param $key
|
||||
* If null, the storage is set to the key of each storage interface it implements
|
||||
*
|
||||
* @see storageMap
|
||||
*/
|
||||
public function addStorage($storage, $key = null)
|
||||
{
|
||||
// if explicitly set to a valid key, do not "magically" set below
|
||||
if (isset($this->storageMap[$key])) {
|
||||
if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) {
|
||||
throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key]));
|
||||
}
|
||||
$this->storages[$key] = $storage;
|
||||
|
||||
// special logic to handle "client" and "client_credentials" strangeness
|
||||
if ($key === 'client' && !isset($this->storages['client_credentials'])) {
|
||||
if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) {
|
||||
$this->storages['client_credentials'] = $storage;
|
||||
}
|
||||
} elseif ($key === 'client_credentials' && !isset($this->storages['client'])) {
|
||||
if ($storage instanceof \OAuth2\Storage\ClientInterface) {
|
||||
$this->storages['client'] = $storage;
|
||||
}
|
||||
}
|
||||
} elseif (!is_null($key) && !is_numeric($key)) {
|
||||
throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap))));
|
||||
} else {
|
||||
$set = false;
|
||||
foreach ($this->storageMap as $type => $interface) {
|
||||
if ($storage instanceof $interface) {
|
||||
$this->storages[$type] = $storage;
|
||||
$set = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$set) {
|
||||
throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addResponseType(ResponseTypeInterface $responseType, $key = null)
|
||||
{
|
||||
$key = $this->normalizeResponseType($key);
|
||||
|
||||
if (isset($this->responseTypeMap[$key])) {
|
||||
if (!$responseType instanceof $this->responseTypeMap[$key]) {
|
||||
throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key]));
|
||||
}
|
||||
$this->responseTypes[$key] = $responseType;
|
||||
} elseif (!is_null($key) && !is_numeric($key)) {
|
||||
throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap))));
|
||||
} else {
|
||||
$set = false;
|
||||
foreach ($this->responseTypeMap as $type => $interface) {
|
||||
if ($responseType instanceof $interface) {
|
||||
$this->responseTypes[$type] = $responseType;
|
||||
$set = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$set) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown response type %s. Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getScopeUtil()
|
||||
{
|
||||
if (!$this->scopeUtil) {
|
||||
$storage = isset($this->storages['scope']) ? $this->storages['scope'] : null;
|
||||
$this->scopeUtil = new Scope($storage);
|
||||
}
|
||||
|
||||
return $this->scopeUtil;
|
||||
}
|
||||
|
||||
/**
|
||||
* every getter deserves a setter
|
||||
*/
|
||||
public function setScopeUtil($scopeUtil)
|
||||
{
|
||||
$this->scopeUtil = $scopeUtil;
|
||||
}
|
||||
|
||||
protected function createDefaultAuthorizeController()
|
||||
{
|
||||
if (!isset($this->storages['client'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server");
|
||||
}
|
||||
if (0 == count($this->responseTypes)) {
|
||||
$this->responseTypes = $this->getDefaultResponseTypes();
|
||||
}
|
||||
if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) {
|
||||
$this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType();
|
||||
if ($this->config['allow_implicit']) {
|
||||
$this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType();
|
||||
}
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri')));
|
||||
|
||||
if ($this->config['use_openid_connect']) {
|
||||
return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
|
||||
}
|
||||
|
||||
return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
|
||||
}
|
||||
|
||||
protected function createDefaultTokenController()
|
||||
{
|
||||
if (0 == count($this->grantTypes)) {
|
||||
$this->grantTypes = $this->getDefaultGrantTypes();
|
||||
}
|
||||
|
||||
if (is_null($this->clientAssertionType)) {
|
||||
// see if HttpBasic assertion type is requred. If so, then create it from storage classes.
|
||||
foreach ($this->grantTypes as $grantType) {
|
||||
if (!$grantType instanceof ClientAssertionTypeInterface) {
|
||||
if (!isset($this->storages['client_credentials'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server");
|
||||
}
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients')));
|
||||
$this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->storages['client'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server");
|
||||
}
|
||||
|
||||
$accessTokenResponseType = $this->getAccessTokenResponseType();
|
||||
|
||||
return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
|
||||
}
|
||||
|
||||
protected function createDefaultResourceController()
|
||||
{
|
||||
if ($this->config['use_jwt_access_tokens']) {
|
||||
// overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
|
||||
if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
|
||||
$this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
|
||||
}
|
||||
} elseif (!isset($this->storages['access_token'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server");
|
||||
}
|
||||
|
||||
if (!$this->tokenType) {
|
||||
$this->tokenType = $this->getDefaultTokenType();
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array('www_realm' => ''));
|
||||
|
||||
return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil());
|
||||
}
|
||||
|
||||
protected function createDefaultUserInfoController()
|
||||
{
|
||||
if ($this->config['use_jwt_access_tokens']) {
|
||||
// overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
|
||||
if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
|
||||
$this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
|
||||
}
|
||||
} elseif (!isset($this->storages['access_token'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server");
|
||||
}
|
||||
|
||||
if (!isset($this->storages['user_claims'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server");
|
||||
}
|
||||
|
||||
if (!$this->tokenType) {
|
||||
$this->tokenType = $this->getDefaultTokenType();
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array('www_realm' => ''));
|
||||
|
||||
return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil());
|
||||
}
|
||||
|
||||
protected function getDefaultTokenType()
|
||||
{
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name')));
|
||||
|
||||
return new Bearer($config);
|
||||
}
|
||||
|
||||
protected function getDefaultResponseTypes()
|
||||
{
|
||||
$responseTypes = array();
|
||||
|
||||
if ($this->config['allow_implicit']) {
|
||||
$responseTypes['token'] = $this->getAccessTokenResponseType();
|
||||
}
|
||||
|
||||
if ($this->config['use_openid_connect']) {
|
||||
$responseTypes['id_token'] = $this->getIdTokenResponseType();
|
||||
if ($this->config['allow_implicit']) {
|
||||
$responseTypes['id_token token'] = $this->getIdTokenTokenResponseType();
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->storages['authorization_code'])) {
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime')));
|
||||
if ($this->config['use_openid_connect']) {
|
||||
if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
|
||||
throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
|
||||
}
|
||||
$responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config);
|
||||
$responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']);
|
||||
} else {
|
||||
$responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($responseTypes) == 0) {
|
||||
throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object");
|
||||
}
|
||||
|
||||
return $responseTypes;
|
||||
}
|
||||
|
||||
protected function getDefaultGrantTypes()
|
||||
{
|
||||
$grantTypes = array();
|
||||
|
||||
if (isset($this->storages['user_credentials'])) {
|
||||
$grantTypes['password'] = new UserCredentials($this->storages['user_credentials']);
|
||||
}
|
||||
|
||||
if (isset($this->storages['client_credentials'])) {
|
||||
$config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => ''));
|
||||
$grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config);
|
||||
}
|
||||
|
||||
if (isset($this->storages['refresh_token'])) {
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use')));
|
||||
$grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config);
|
||||
}
|
||||
|
||||
if (isset($this->storages['authorization_code'])) {
|
||||
if ($this->config['use_openid_connect']) {
|
||||
if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
|
||||
throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
|
||||
}
|
||||
$grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']);
|
||||
} else {
|
||||
$grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($grantTypes) == 0) {
|
||||
throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor");
|
||||
}
|
||||
|
||||
return $grantTypes;
|
||||
}
|
||||
|
||||
protected function getAccessTokenResponseType()
|
||||
{
|
||||
if (isset($this->responseTypes['token'])) {
|
||||
return $this->responseTypes['token'];
|
||||
}
|
||||
|
||||
if ($this->config['use_jwt_access_tokens']) {
|
||||
return $this->createDefaultJwtAccessTokenResponseType();
|
||||
}
|
||||
|
||||
return $this->createDefaultAccessTokenResponseType();
|
||||
}
|
||||
|
||||
protected function getIdTokenResponseType()
|
||||
{
|
||||
if (isset($this->responseTypes['id_token'])) {
|
||||
return $this->responseTypes['id_token'];
|
||||
}
|
||||
|
||||
return $this->createDefaultIdTokenResponseType();
|
||||
}
|
||||
|
||||
protected function getIdTokenTokenResponseType()
|
||||
{
|
||||
if (isset($this->responseTypes['id_token token'])) {
|
||||
return $this->responseTypes['id_token token'];
|
||||
}
|
||||
|
||||
return $this->createDefaultIdTokenTokenResponseType();
|
||||
}
|
||||
|
||||
/**
|
||||
* For Resource Controller
|
||||
*/
|
||||
protected function createDefaultJwtAccessTokenStorage()
|
||||
{
|
||||
if (!isset($this->storages['public_key'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
|
||||
}
|
||||
$tokenStorage = null;
|
||||
if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) {
|
||||
$tokenStorage = $this->storages['access_token'];
|
||||
}
|
||||
// wrap the access token storage as required.
|
||||
return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* For Authorize and Token Controllers
|
||||
*/
|
||||
protected function createDefaultJwtAccessTokenResponseType()
|
||||
{
|
||||
if (!isset($this->storages['public_key'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
|
||||
}
|
||||
|
||||
$tokenStorage = null;
|
||||
if (isset($this->storages['access_token'])) {
|
||||
$tokenStorage = $this->storages['access_token'];
|
||||
}
|
||||
|
||||
$refreshStorage = null;
|
||||
if (isset($this->storages['refresh_token'])) {
|
||||
$refreshStorage = $this->storages['refresh_token'];
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime')));
|
||||
|
||||
return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
|
||||
}
|
||||
|
||||
protected function createDefaultAccessTokenResponseType()
|
||||
{
|
||||
if (!isset($this->storages['access_token'])) {
|
||||
throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server");
|
||||
}
|
||||
|
||||
$refreshStorage = null;
|
||||
if (isset($this->storages['refresh_token'])) {
|
||||
$refreshStorage = $this->storages['refresh_token'];
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime')));
|
||||
$config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() : $this->getDefaultTokenType()->getTokenType();
|
||||
|
||||
return new AccessToken($this->storages['access_token'], $refreshStorage, $config);
|
||||
}
|
||||
|
||||
protected function createDefaultIdTokenResponseType()
|
||||
{
|
||||
if (!isset($this->storages['user_claims'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect");
|
||||
}
|
||||
if (!isset($this->storages['public_key'])) {
|
||||
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
|
||||
}
|
||||
|
||||
$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
|
||||
|
||||
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
|
||||
}
|
||||
|
||||
protected function createDefaultIdTokenTokenResponseType()
|
||||
{
|
||||
return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
|
||||
}
|
||||
|
||||
protected function validateOpenIdConnect()
|
||||
{
|
||||
$authCodeGrant = $this->getGrantType('authorization_code');
|
||||
if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) {
|
||||
throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function normalizeResponseType($name)
|
||||
{
|
||||
// for multiple-valued response types - make them alphabetical
|
||||
if (!empty($name) && false !== strpos($name, ' ')) {
|
||||
$types = explode(' ', $name);
|
||||
sort($types);
|
||||
$name = implode(' ', $types);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function getStorages()
|
||||
{
|
||||
return $this->storages;
|
||||
}
|
||||
|
||||
public function getStorage($name)
|
||||
{
|
||||
return isset($this->storages[$name]) ? $this->storages[$name] : null;
|
||||
}
|
||||
|
||||
public function getGrantTypes()
|
||||
{
|
||||
return $this->grantTypes;
|
||||
}
|
||||
|
||||
public function getGrantType($name)
|
||||
{
|
||||
return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null;
|
||||
}
|
||||
|
||||
public function getResponseTypes()
|
||||
{
|
||||
return $this->responseTypes;
|
||||
}
|
||||
|
||||
public function getResponseType($name)
|
||||
{
|
||||
// for multiple-valued response types - make them alphabetical
|
||||
$name = $this->normalizeResponseType($name);
|
||||
|
||||
return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null;
|
||||
}
|
||||
|
||||
public function getTokenType()
|
||||
{
|
||||
return $this->tokenType;
|
||||
}
|
||||
|
||||
public function getClientAssertionType()
|
||||
{
|
||||
return $this->clientAssertionType;
|
||||
}
|
||||
|
||||
public function setConfig($name, $value)
|
||||
{
|
||||
$this->config[$name] = $value;
|
||||
}
|
||||
|
||||
public function getConfig($name, $default = null)
|
||||
{
|
||||
return isset($this->config[$name]) ? $this->config[$name] : $default;
|
||||
}
|
||||
}
|
63
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php
vendored
Normal file
63
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AccessTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get/save access tokens
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AccessTokenInterface
|
||||
{
|
||||
/**
|
||||
* Look up the supplied oauth_token from storage.
|
||||
*
|
||||
* We need to retrieve access token data as we create and verify tokens.
|
||||
*
|
||||
* @param $oauth_token
|
||||
* oauth_token to be check with.
|
||||
*
|
||||
* @return
|
||||
* An associative array as below, and return NULL if the supplied oauth_token
|
||||
* is invalid:
|
||||
* - expires: Stored expiration in unix timestamp.
|
||||
* - client_id: (optional) Stored client identifier.
|
||||
* - user_id: (optional) Stored user identifier.
|
||||
* - scope: (optional) Stored scope values in space-separated string.
|
||||
* - id_token: (optional) Stored id_token (if "use_openid_connect" is true).
|
||||
*
|
||||
* @ingroup oauth2_section_7
|
||||
*/
|
||||
public function getAccessToken($oauth_token);
|
||||
|
||||
/**
|
||||
* Store the supplied access token values to storage.
|
||||
*
|
||||
* We need to store access token data as we create and verify tokens.
|
||||
*
|
||||
* @param $oauth_token oauth_token to be stored.
|
||||
* @param $client_id client identifier to be stored.
|
||||
* @param $user_id user identifier to be stored.
|
||||
* @param int $expires expiration to be stored as a Unix timestamp.
|
||||
* @param string $scope OPTIONAL Scopes to be stored in space-separated string.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null);
|
||||
|
||||
/**
|
||||
* Expire an access token.
|
||||
*
|
||||
* This is not explicitly required in the spec, but if defined in a draft RFC for token
|
||||
* revoking (RFC 7009) https://tools.ietf.org/html/rfc7009
|
||||
*
|
||||
* @param $access_token
|
||||
* Access token to be expired.
|
||||
*
|
||||
* @ingroup oauth2_section_6
|
||||
*
|
||||
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
|
||||
*/
|
||||
//public function unsetAccessToken($access_token);
|
||||
}
|
86
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php
vendored
Normal file
86
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/AuthorizationCodeInterface.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get/save authorization codes for the "Authorization Code"
|
||||
* grant type
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface AuthorizationCodeInterface
|
||||
{
|
||||
/**
|
||||
* The Authorization Code grant type supports a response type of "code".
|
||||
*
|
||||
* @var string
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-1.4.1
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.2
|
||||
*/
|
||||
const RESPONSE_TYPE_CODE = "code";
|
||||
|
||||
/**
|
||||
* Fetch authorization code data (probably the most common grant type).
|
||||
*
|
||||
* Retrieve the stored data for the given authorization code.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
|
||||
*
|
||||
* @param $code
|
||||
* Authorization code to be check with.
|
||||
*
|
||||
* @return
|
||||
* An associative array as below, and NULL if the code is invalid
|
||||
* @code
|
||||
* return array(
|
||||
* "client_id" => CLIENT_ID, // REQUIRED Stored client identifier
|
||||
* "user_id" => USER_ID, // REQUIRED Stored user identifier
|
||||
* "expires" => EXPIRES, // REQUIRED Stored expiration in unix timestamp
|
||||
* "redirect_uri" => REDIRECT_URI, // REQUIRED Stored redirect URI
|
||||
* "scope" => SCOPE, // OPTIONAL Stored scope values in space-separated string
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function getAuthorizationCode($code);
|
||||
|
||||
/**
|
||||
* Take the provided authorization code values and store them somewhere.
|
||||
*
|
||||
* This function should be the storage counterpart to getAuthCode().
|
||||
*
|
||||
* If storage fails for some reason, we're not currently checking for
|
||||
* any sort of success/failure, so you should bail out of the script
|
||||
* and provide a descriptive fail message.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_AUTH_CODE.
|
||||
*
|
||||
* @param string $code Authorization code to be stored.
|
||||
* @param mixed $client_id Client identifier to be stored.
|
||||
* @param mixed $user_id User identifier to be stored.
|
||||
* @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string.
|
||||
* @param int $expires Expiration to be stored as a Unix timestamp.
|
||||
* @param string $scope OPTIONAL Scopes to be stored in space-separated string.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null);
|
||||
|
||||
/**
|
||||
* once an Authorization Code is used, it must be exipired
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.1.2
|
||||
*
|
||||
* The client MUST NOT use the authorization code
|
||||
* more than once. If an authorization code is used more than
|
||||
* once, the authorization server MUST deny the request and SHOULD
|
||||
* revoke (when possible) all tokens previously issued based on
|
||||
* that authorization code
|
||||
*
|
||||
*/
|
||||
public function expireAuthorizationCode($code);
|
||||
}
|
469
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php
vendored
Normal file
469
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Cassandra.php
vendored
Normal file
|
@ -0,0 +1,469 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use phpcassa\ColumnFamily;
|
||||
use phpcassa\ColumnSlice;
|
||||
use phpcassa\Connection\ConnectionPool;
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
* Cassandra storage for all storage types
|
||||
*
|
||||
* To use, install "thobbs/phpcassa" via composer
|
||||
* <code>
|
||||
* composer require thobbs/phpcassa:dev-master
|
||||
* </code>
|
||||
*
|
||||
* Once this is done, instantiate the
|
||||
* <code>
|
||||
* $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160'));
|
||||
* </code>
|
||||
*
|
||||
* Then, register the storage client:
|
||||
* <code>
|
||||
* $storage = new OAuth2\Storage\Cassandra($cassandra);
|
||||
* $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
|
||||
* </code>
|
||||
*
|
||||
* @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage
|
||||
*/
|
||||
class Cassandra implements AuthorizationCodeInterface,
|
||||
AccessTokenInterface,
|
||||
ClientCredentialsInterface,
|
||||
UserCredentialsInterface,
|
||||
RefreshTokenInterface,
|
||||
JwtBearerInterface,
|
||||
ScopeInterface,
|
||||
PublicKeyInterface,
|
||||
UserClaimsInterface,
|
||||
OpenIDAuthorizationCodeInterface
|
||||
{
|
||||
|
||||
private $cache;
|
||||
|
||||
/* The cassandra client */
|
||||
protected $cassandra;
|
||||
|
||||
/* Configuration array */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Cassandra Storage! uses phpCassa
|
||||
*
|
||||
* @param \phpcassa\ConnectionPool $cassandra
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($connection = array(), array $config = array())
|
||||
{
|
||||
if ($connection instanceof ConnectionPool) {
|
||||
$this->cassandra = $connection;
|
||||
} else {
|
||||
if (!is_array($connection)) {
|
||||
throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array');
|
||||
}
|
||||
$connection = array_merge(array(
|
||||
'keyspace' => 'oauth2',
|
||||
'servers' => null,
|
||||
), $connection);
|
||||
|
||||
$this->cassandra = new ConnectionPool($connection['keyspace'], $connection['servers']);
|
||||
}
|
||||
|
||||
$this->config = array_merge(array(
|
||||
// cassandra config
|
||||
'column_family' => 'auth',
|
||||
|
||||
// key names
|
||||
'client_key' => 'oauth_clients:',
|
||||
'access_token_key' => 'oauth_access_tokens:',
|
||||
'refresh_token_key' => 'oauth_refresh_tokens:',
|
||||
'code_key' => 'oauth_authorization_codes:',
|
||||
'user_key' => 'oauth_users:',
|
||||
'jwt_key' => 'oauth_jwt:',
|
||||
'scope_key' => 'oauth_scopes:',
|
||||
'public_key_key' => 'oauth_public_keys:',
|
||||
), $config);
|
||||
}
|
||||
|
||||
protected function getValue($key)
|
||||
{
|
||||
if (isset($this->cache[$key])) {
|
||||
return $this->cache[$key];
|
||||
}
|
||||
$cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
|
||||
|
||||
try {
|
||||
$value = $cf->get($key, new ColumnSlice("", ""));
|
||||
$value = array_shift($value);
|
||||
} catch (\cassandra\NotFoundException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode($value, true);
|
||||
}
|
||||
|
||||
protected function setValue($key, $value, $expire = 0)
|
||||
{
|
||||
$this->cache[$key] = $value;
|
||||
|
||||
$cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
|
||||
|
||||
$str = json_encode($value);
|
||||
if ($expire > 0) {
|
||||
try {
|
||||
$seconds = $expire - time();
|
||||
// __data key set as C* requires a field, note: max TTL can only be 630720000 seconds
|
||||
$cf->insert($key, array('__data' => $str), null, $seconds);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// __data key set as C* requires a field
|
||||
$cf->insert($key, array('__data' => $str));
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function expireValue($key)
|
||||
{
|
||||
unset($this->cache[$key]);
|
||||
|
||||
$cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
|
||||
try {
|
||||
// __data key set as C* requires a field
|
||||
$cf->remove($key, array('__data'));
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
return $this->getValue($this->config['code_key'] . $code);
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['code_key'] . $authorization_code,
|
||||
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
$key = $this->config['code_key'] . $code;
|
||||
unset($this->cache[$key]);
|
||||
|
||||
return $this->expireValue($key);
|
||||
}
|
||||
|
||||
/* UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
return $this->checkPassword($user, $password);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// plaintext passwords are bad! Override this for your application
|
||||
protected function checkPassword($user, $password)
|
||||
{
|
||||
return $user['password'] == sha1($password);
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
return $this->getUser($username);
|
||||
}
|
||||
|
||||
public function getUser($username)
|
||||
{
|
||||
if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the default behavior is to use "username" as the user_id
|
||||
return array_merge(array(
|
||||
'user_id' => $username,
|
||||
), $userInfo);
|
||||
}
|
||||
|
||||
public function setUser($username, $password, $first_name = null, $last_name = null)
|
||||
{
|
||||
$password = sha1($password);
|
||||
|
||||
return $this->setValue(
|
||||
$this->config['user_key'] . $username,
|
||||
compact('username', 'password', 'first_name', 'last_name')
|
||||
);
|
||||
}
|
||||
|
||||
/* ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
if (!$client = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($client['client_secret'])
|
||||
&& $client['client_secret'] == $client_secret;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
if (!$client = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($result['client_secret']);;
|
||||
}
|
||||
|
||||
/* ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
return $this->getValue($this->config['client_key'] . $client_id);
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['client_key'] . $client_id,
|
||||
compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')
|
||||
);
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
$details = $this->getClientDetails($client_id);
|
||||
if (isset($details['grant_types'])) {
|
||||
$grant_types = explode(' ', $details['grant_types']);
|
||||
|
||||
return in_array($grant_type, (array) $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['refresh_token_key'] . $refresh_token,
|
||||
compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
|
||||
}
|
||||
|
||||
/* AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
return $this->getValue($this->config['access_token_key'].$access_token);
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['access_token_key'].$access_token,
|
||||
compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
return $this->expireValue($this->config['access_token_key'] . $access_token);
|
||||
}
|
||||
|
||||
/* ScopeInterface */
|
||||
public function scopeExists($scope)
|
||||
{
|
||||
$scope = explode(' ', $scope);
|
||||
|
||||
$result = $this->getValue($this->config['scope_key'].'supported:global');
|
||||
|
||||
$supportedScope = explode(' ', (string) $result);
|
||||
|
||||
return (count(array_diff($scope, $supportedScope)) == 0);
|
||||
}
|
||||
|
||||
public function getDefaultScope($client_id = null)
|
||||
{
|
||||
if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
|
||||
$result = $this->getValue($this->config['scope_key'].'default:global');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function setScope($scope, $client_id = null, $type = 'supported')
|
||||
{
|
||||
if (!in_array($type, array('default', 'supported'))) {
|
||||
throw new \InvalidArgumentException('"$type" must be one of "default", "supported"');
|
||||
}
|
||||
|
||||
if (is_null($client_id)) {
|
||||
$key = $this->config['scope_key'].$type.':global';
|
||||
} else {
|
||||
$key = $this->config['scope_key'].$type.':'.$client_id;
|
||||
}
|
||||
|
||||
return $this->setValue($key, $scope);
|
||||
}
|
||||
|
||||
/*JWTBearerInterface */
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($jwt['subject']) && $jwt['subject'] == $subject ) {
|
||||
return $jwt['key'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setClientKey($client_id, $key, $subject = null)
|
||||
{
|
||||
return $this->setValue($this->config['jwt_key'] . $client_id, array(
|
||||
'key' => $key,
|
||||
'subject' => $subject
|
||||
));
|
||||
}
|
||||
|
||||
/*ScopeInterface */
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs cassandra implementation.
|
||||
throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.');
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs cassandra implementation.
|
||||
throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
|
||||
}
|
||||
|
||||
/* PublicKeyInterface */
|
||||
public function getPublicKey($client_id = '')
|
||||
{
|
||||
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['public_key'];
|
||||
}
|
||||
$public_key = $this->getValue($this->config['public_key_key']);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['public_key'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrivateKey($client_id = '')
|
||||
{
|
||||
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['private_key'];
|
||||
}
|
||||
$public_key = $this->getValue($this->config['public_key_key']);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['private_key'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getEncryptionAlgorithm($client_id = null)
|
||||
{
|
||||
$public_key = $this->getValue($this->config['public_key_key'] . $client_id);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['encryption_algorithm'];
|
||||
}
|
||||
$public_key = $this->getValue($this->config['public_key_key']);
|
||||
if (is_array($public_key)) {
|
||||
return $public_key['encryption_algorithm'];
|
||||
}
|
||||
|
||||
return 'RS256';
|
||||
}
|
||||
|
||||
/* UserClaimsInterface */
|
||||
public function getUserClaims($user_id, $claims)
|
||||
{
|
||||
$userDetails = $this->getUserDetails($user_id);
|
||||
if (!is_array($userDetails)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$claims = explode(' ', trim($claims));
|
||||
$userClaims = array();
|
||||
|
||||
// for each requested claim, if the user has the claim, set it in the response
|
||||
$validClaims = explode(' ', self::VALID_CLAIMS);
|
||||
foreach ($validClaims as $validClaim) {
|
||||
if (in_array($validClaim, $claims)) {
|
||||
if ($validClaim == 'address') {
|
||||
// address is an object with subfields
|
||||
$userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
|
||||
} else {
|
||||
$userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
protected function getUserClaim($claim, $userDetails)
|
||||
{
|
||||
$userClaims = array();
|
||||
$claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
|
||||
$claimValues = explode(' ', $claimValuesString);
|
||||
|
||||
foreach ($claimValues as $value) {
|
||||
if ($value == 'email_verified') {
|
||||
$userClaims[$value] = $userDetails[$value]=='true' ? true : false;
|
||||
} else {
|
||||
$userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
}
|
49
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php
vendored
Normal file
49
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientCredentialsInterface.php
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify how the OAuth2 Server
|
||||
* should verify client credentials
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface ClientCredentialsInterface extends ClientInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Make sure that the client credentials is valid.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to be check with.
|
||||
* @param $client_secret
|
||||
* (optional) If a secret is required, check that they've given the right one.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the client credentials are valid, and MUST return FALSE if it isn't.
|
||||
* @endcode
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-3.1
|
||||
*
|
||||
* @ingroup oauth2_section_3
|
||||
*/
|
||||
public function checkClientCredentials($client_id, $client_secret = null);
|
||||
|
||||
/**
|
||||
* Determine if the client is a "public" client, and therefore
|
||||
* does not require passing credentials for certain grant types
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to be check with.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the client is public, and FALSE if it isn't.
|
||||
* @endcode
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-2.3
|
||||
* @see https://github.com/bshaffer/oauth2-server-php/issues/257
|
||||
*
|
||||
* @ingroup oauth2_section_2
|
||||
*/
|
||||
public function isPublicClient($client_id);
|
||||
}
|
66
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php
vendored
Normal file
66
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ClientInterface.php
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should retrieve client information
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface ClientInterface
|
||||
{
|
||||
/**
|
||||
* Get client details corresponding client_id.
|
||||
*
|
||||
* OAuth says we should store request URIs for each registered client.
|
||||
* Implement this function to grab the stored URI for a given client id.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to be check with.
|
||||
*
|
||||
* @return array
|
||||
* Client details. The only mandatory key in the array is "redirect_uri".
|
||||
* This function MUST return FALSE if the given client does not exist or is
|
||||
* invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris.
|
||||
* <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
|
||||
*/
|
||||
public function getClientDetails($client_id);
|
||||
|
||||
/**
|
||||
* Get the scope associated with this client
|
||||
*
|
||||
* @return
|
||||
* STRING the space-delineated scope list for the specified client_id
|
||||
*/
|
||||
public function getClientScope($client_id);
|
||||
|
||||
/**
|
||||
* Check restricted grant types of corresponding client identifier.
|
||||
*
|
||||
* If you want to restrict clients to certain grant types, override this
|
||||
* function.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to be check with.
|
||||
* @param $grant_type
|
||||
* Grant type to be check with
|
||||
*
|
||||
* @return
|
||||
* TRUE if the grant type is supported by this client identifier, and
|
||||
* FALSE if it isn't.
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function checkRestrictedGrantType($client_id, $grant_type);
|
||||
}
|
331
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php
vendored
Executable file
331
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/CouchbaseDB.php
vendored
Executable file
|
@ -0,0 +1,331 @@
|
|||
<?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
|
||||
{
|
||||
protected $db;
|
||||
protected $config;
|
||||
|
||||
public function __construct($connection, $config = array())
|
||||
{
|
||||
if ($connection instanceof \Couchbase) {
|
||||
$this->db = $connection;
|
||||
} else {
|
||||
if (!is_array($connection) || !is_array($connection['servers'])) {
|
||||
throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array');
|
||||
}
|
||||
|
||||
$this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
|
||||
}
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'client_table' => 'oauth_clients',
|
||||
'access_token_table' => 'oauth_access_tokens',
|
||||
'refresh_token_table' => 'oauth_refresh_tokens',
|
||||
'code_table' => 'oauth_authorization_codes',
|
||||
'user_table' => 'oauth_users',
|
||||
'jwt_table' => 'oauth_jwt',
|
||||
), $config);
|
||||
}
|
||||
|
||||
// Helper function to access couchbase item by type:
|
||||
protected function getObjectByType($name,$id)
|
||||
{
|
||||
return json_decode($this->db->get($this->config[$name].'-'.$id),true);
|
||||
}
|
||||
|
||||
// Helper function to set couchbase item by type:
|
||||
protected function setObjectByType($name,$id,$array)
|
||||
{
|
||||
$array['type'] = $name;
|
||||
|
||||
return $this->db->set($this->config[$name].'-'.$id,json_encode($array));
|
||||
}
|
||||
|
||||
// Helper function to delete couchbase item by type, wait for persist to at least 1 node
|
||||
protected function deleteObjectByType($name,$id)
|
||||
{
|
||||
$this->db->delete($this->config[$name].'-'.$id,"",1);
|
||||
}
|
||||
|
||||
/* ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
if ($result = $this->getObjectByType('client_table',$client_id)) {
|
||||
return $result['client_secret'] == $client_secret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
if (!$result = $this->getObjectByType('client_table',$client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($result['client_secret']);
|
||||
}
|
||||
|
||||
/* ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
$result = $this->getObjectByType('client_table',$client_id);
|
||||
|
||||
return is_null($result) ? false : $result;
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
if ($this->getClientDetails($client_id)) {
|
||||
|
||||
$this->setObjectByType('client_table',$client_id, array(
|
||||
'client_id' => $client_id,
|
||||
'client_secret' => $client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_types' => $grant_types,
|
||||
'scope' => $scope,
|
||||
'user_id' => $user_id,
|
||||
));
|
||||
} else {
|
||||
$this->setObjectByType('client_table',$client_id, array(
|
||||
'client_id' => $client_id,
|
||||
'client_secret' => $client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_types' => $grant_types,
|
||||
'scope' => $scope,
|
||||
'user_id' => $user_id,
|
||||
));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
$details = $this->getClientDetails($client_id);
|
||||
if (isset($details['grant_types'])) {
|
||||
$grant_types = explode(' ', $details['grant_types']);
|
||||
|
||||
return in_array($grant_type, $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
/* AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
$token = $this->getObjectByType('access_token_table',$access_token);
|
||||
|
||||
return is_null($token) ? false : $token;
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
// if it exists, update it.
|
||||
if ($this->getAccessToken($access_token)) {
|
||||
$this->setObjectByType('access_token_table',$access_token, array(
|
||||
'access_token' => $access_token,
|
||||
'client_id' => $client_id,
|
||||
'expires' => $expires,
|
||||
'user_id' => $user_id,
|
||||
'scope' => $scope
|
||||
));
|
||||
} else {
|
||||
$this->setObjectByType('access_token_table',$access_token, array(
|
||||
'access_token' => $access_token,
|
||||
'client_id' => $client_id,
|
||||
'expires' => $expires,
|
||||
'user_id' => $user_id,
|
||||
'scope' => $scope
|
||||
));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
$code = $this->getObjectByType('code_table',$code);
|
||||
|
||||
return is_null($code) ? false : $code;
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
// if it exists, update it.
|
||||
if ($this->getAuthorizationCode($code)) {
|
||||
$this->setObjectByType('code_table',$code, array(
|
||||
'authorization_code' => $code,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope,
|
||||
'id_token' => $id_token,
|
||||
));
|
||||
} else {
|
||||
$this->setObjectByType('code_table',$code,array(
|
||||
'authorization_code' => $code,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope,
|
||||
'id_token' => $id_token,
|
||||
));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
$this->deleteObjectByType('code_table',$code);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
return $this->checkPassword($user, $password);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
$user['user_id'] = $user['username'];
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/* RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
$token = $this->getObjectByType('refresh_token_table',$refresh_token);
|
||||
|
||||
return is_null($token) ? false : $token;
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
$this->setObjectByType('refresh_token_table',$refresh_token, array(
|
||||
'refresh_token' => $refresh_token,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
$this->deleteObjectByType('refresh_token_table',$refresh_token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// plaintext passwords are bad! Override this for your application
|
||||
protected function checkPassword($user, $password)
|
||||
{
|
||||
return $user['password'] == $password;
|
||||
}
|
||||
|
||||
public function getUser($username)
|
||||
{
|
||||
$result = $this->getObjectByType('user_table',$username);
|
||||
|
||||
return is_null($result) ? false : $result;
|
||||
}
|
||||
|
||||
public function setUser($username, $password, $firstName = null, $lastName = null)
|
||||
{
|
||||
if ($this->getUser($username)) {
|
||||
$this->setObjectByType('user_table',$username, array(
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName
|
||||
));
|
||||
|
||||
} else {
|
||||
$this->setObjectByType('user_table',$username, array(
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
if (!$jwt = $this->getObjectByType('jwt_table',$client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
|
||||
return $jwt['key'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs couchbase implementation.
|
||||
throw new \Exception('getJti() for the Couchbase driver is currently unimplemented.');
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs couchbase implementation.
|
||||
throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.');
|
||||
}
|
||||
}
|
528
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php
vendored
Normal file
528
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/DynamoDB.php
vendored
Normal file
|
@ -0,0 +1,528 @@
|
|||
<?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 !empty($value); });
|
||||
|
||||
$result = $this->client->putItem(array(
|
||||
'TableName' => $this->config['access_token_table'],
|
||||
'Item' => $this->client->formatAttributes($clientData)
|
||||
));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
$result = $this->client->deleteItem(array(
|
||||
'TableName' => $this->config['access_token_table'],
|
||||
'Key' => $this->client->formatAttributes(array("access_token" => $access_token))
|
||||
));
|
||||
|
||||
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 !empty($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 !empty($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 empty($defaultScope) ? null : implode(' ', $defaultScope);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* JWTBearerInterface */
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
$result = $this->client->getItem(array(
|
||||
"TableName"=> $this->config['jwt_table'],
|
||||
"Key" => array('client_id' => array('S' => $client_id), 'subject' => array('S' => $subject))
|
||||
));
|
||||
if ($result->count()==0) {
|
||||
return false ;
|
||||
}
|
||||
$token = $this->dynamo2array($result);
|
||||
|
||||
return $token['public_key'];
|
||||
}
|
||||
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
//TODO not use.
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
//TODO not use.
|
||||
}
|
||||
|
||||
/* PublicKeyInterface */
|
||||
public function getPublicKey($client_id = '0')
|
||||
{
|
||||
|
||||
$result = $this->client->getItem(array(
|
||||
"TableName"=> $this->config['public_key_table'],
|
||||
"Key" => array('client_id' => array('S' => $client_id))
|
||||
));
|
||||
if ($result->count()==0) {
|
||||
return false ;
|
||||
}
|
||||
$token = $this->dynamo2array($result);
|
||||
|
||||
return $token['public_key'];
|
||||
|
||||
}
|
||||
|
||||
public function getPrivateKey($client_id = '0')
|
||||
{
|
||||
$result = $this->client->getItem(array(
|
||||
"TableName"=> $this->config['public_key_table'],
|
||||
"Key" => array('client_id' => array('S' => $client_id))
|
||||
));
|
||||
if ($result->count()==0) {
|
||||
return false ;
|
||||
}
|
||||
$token = $this->dynamo2array($result);
|
||||
|
||||
return $token['private_key'];
|
||||
}
|
||||
|
||||
public function getEncryptionAlgorithm($client_id = null)
|
||||
{
|
||||
$result = $this->client->getItem(array(
|
||||
"TableName"=> $this->config['public_key_table'],
|
||||
"Key" => array('client_id' => array('S' => $client_id))
|
||||
));
|
||||
if ($result->count()==0) {
|
||||
return 'RS256' ;
|
||||
}
|
||||
$token = $this->dynamo2array($result);
|
||||
|
||||
return $token['encryption_algorithm'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform dynamodb resultset to an array.
|
||||
* @param $dynamodbResult
|
||||
* @return $array
|
||||
*/
|
||||
private function dynamo2array($dynamodbResult)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($dynamodbResult["Item"] as $key => $val) {
|
||||
$result[$key] = $val["S"];
|
||||
$result[] = $val["S"];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
88
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php
vendored
Normal file
88
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessToken.php
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use OAuth2\Encryption\EncryptionInterface;
|
||||
use OAuth2\Encryption\Jwt;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class JwtAccessToken implements JwtAccessTokenInterface
|
||||
{
|
||||
protected $publicKeyStorage;
|
||||
protected $tokenStorage;
|
||||
protected $encryptionUtil;
|
||||
|
||||
/**
|
||||
* @param OAuth2\Encryption\PublicKeyInterface $publicKeyStorage the public key encryption to use
|
||||
* @param OAuth2\Storage\AccessTokenInterface $tokenStorage OPTIONAL persist the access token to another storage. This is useful if
|
||||
* you want to retain access token grant information somewhere, but
|
||||
* is not necessary when using this grant type.
|
||||
* @param OAuth2\Encryption\EncryptionInterface $encryptionUtil OPTIONAL class to use for "encode" and "decode" functions.
|
||||
*/
|
||||
public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null)
|
||||
{
|
||||
$this->publicKeyStorage = $publicKeyStorage;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
if (is_null($encryptionUtil)) {
|
||||
$encryptionUtil = new Jwt;
|
||||
}
|
||||
$this->encryptionUtil = $encryptionUtil;
|
||||
}
|
||||
|
||||
public function getAccessToken($oauth_token)
|
||||
{
|
||||
// just decode the token, don't verify
|
||||
if (!$tokenData = $this->encryptionUtil->decode($oauth_token, null, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$client_id = isset($tokenData['aud']) ? $tokenData['aud'] : null;
|
||||
$public_key = $this->publicKeyStorage->getPublicKey($client_id);
|
||||
$algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
|
||||
|
||||
// now that we have the client_id, verify the token
|
||||
if (false === $this->encryptionUtil->decode($oauth_token, $public_key, array($algorithm))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// normalize the JWT claims to the format expected by other components in this library
|
||||
return $this->convertJwtToOAuth2($tokenData);
|
||||
}
|
||||
|
||||
public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
if ($this->tokenStorage) {
|
||||
return $this->tokenStorage->setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope);
|
||||
}
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
if ($this->tokenStorage) {
|
||||
return $this->tokenStorage->unsetAccessToken($access_token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// converts a JWT access token into an OAuth2-friendly format
|
||||
protected function convertJwtToOAuth2($tokenData)
|
||||
{
|
||||
$keyMapping = array(
|
||||
'aud' => 'client_id',
|
||||
'exp' => 'expires',
|
||||
'sub' => 'user_id'
|
||||
);
|
||||
|
||||
foreach ($keyMapping as $jwtKey => $oauth2Key) {
|
||||
if (isset($tokenData[$jwtKey])) {
|
||||
$tokenData[$oauth2Key] = $tokenData[$jwtKey];
|
||||
unset($tokenData[$jwtKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return $tokenData;
|
||||
}
|
||||
}
|
14
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php
vendored
Normal file
14
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtAccessTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* No specific methods, but allows the library to check "instanceof"
|
||||
* against interface rather than class
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface JwtAccessTokenInterface extends AccessTokenInterface
|
||||
{
|
||||
|
||||
}
|
74
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php
vendored
Normal file
74
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/JwtBearerInterface.php
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get the JWT key for clients
|
||||
*
|
||||
* @TODO consider extending ClientInterface, as this will almost always
|
||||
* be the same storage as retrieving clientData
|
||||
*
|
||||
* @author F21
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface JwtBearerInterface
|
||||
{
|
||||
/**
|
||||
* Get the public key associated with a client_id
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to be checked with.
|
||||
*
|
||||
* @return
|
||||
* STRING Return the public key for the client_id if it exists, and MUST return FALSE if it doesn't.
|
||||
*/
|
||||
public function getClientKey($client_id, $subject);
|
||||
|
||||
/**
|
||||
* Get a jti (JSON token identifier) by matching against the client_id, subject, audience and expiration.
|
||||
*
|
||||
* @param $client_id
|
||||
* Client identifier to match.
|
||||
*
|
||||
* @param $subject
|
||||
* The subject to match.
|
||||
*
|
||||
* @param $audience
|
||||
* The audience to match.
|
||||
*
|
||||
* @param $expiration
|
||||
* The expiration of the jti.
|
||||
*
|
||||
* @param $jti
|
||||
* The jti to match.
|
||||
*
|
||||
* @return
|
||||
* An associative array as below, and return NULL if the jti does not exist.
|
||||
* - issuer: Stored client identifier.
|
||||
* - subject: Stored subject.
|
||||
* - audience: Stored audience.
|
||||
* - expires: Stored expiration in unix timestamp.
|
||||
* - jti: The stored jti.
|
||||
*/
|
||||
public function getJti($client_id, $subject, $audience, $expiration, $jti);
|
||||
|
||||
/**
|
||||
* Store a used jti so that we can check against it to prevent replay attacks.
|
||||
* @param $client_id
|
||||
* Client identifier to insert.
|
||||
*
|
||||
* @param $subject
|
||||
* The subject to insert.
|
||||
*
|
||||
* @param $audience
|
||||
* The audience to insert.
|
||||
*
|
||||
* @param $expiration
|
||||
* The expiration of the jti.
|
||||
*
|
||||
* @param $jti
|
||||
* The jti to insert.
|
||||
*/
|
||||
public function setJti($client_id, $subject, $audience, $expiration, $jti);
|
||||
}
|
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php
vendored
Normal file
369
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Memory.php
vendored
Normal file
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
* Simple in-memory storage for all storage types
|
||||
*
|
||||
* NOTE: This class should never be used in production, and is
|
||||
* a stub class for example use only
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class Memory implements AuthorizationCodeInterface,
|
||||
UserCredentialsInterface,
|
||||
UserClaimsInterface,
|
||||
AccessTokenInterface,
|
||||
ClientCredentialsInterface,
|
||||
RefreshTokenInterface,
|
||||
JwtBearerInterface,
|
||||
ScopeInterface,
|
||||
PublicKeyInterface,
|
||||
OpenIDAuthorizationCodeInterface
|
||||
{
|
||||
public $authorizationCodes;
|
||||
public $userCredentials;
|
||||
public $clientCredentials;
|
||||
public $refreshTokens;
|
||||
public $accessTokens;
|
||||
public $jwt;
|
||||
public $jti;
|
||||
public $supportedScopes;
|
||||
public $defaultScope;
|
||||
public $keys;
|
||||
|
||||
public function __construct($params = array())
|
||||
{
|
||||
$params = array_merge(array(
|
||||
'authorization_codes' => array(),
|
||||
'user_credentials' => array(),
|
||||
'client_credentials' => array(),
|
||||
'refresh_tokens' => array(),
|
||||
'access_tokens' => array(),
|
||||
'jwt' => array(),
|
||||
'jti' => array(),
|
||||
'default_scope' => null,
|
||||
'supported_scopes' => array(),
|
||||
'keys' => array(),
|
||||
), $params);
|
||||
|
||||
$this->authorizationCodes = $params['authorization_codes'];
|
||||
$this->userCredentials = $params['user_credentials'];
|
||||
$this->clientCredentials = $params['client_credentials'];
|
||||
$this->refreshTokens = $params['refresh_tokens'];
|
||||
$this->accessTokens = $params['access_tokens'];
|
||||
$this->jwt = $params['jwt'];
|
||||
$this->jti = $params['jti'];
|
||||
$this->supportedScopes = $params['supported_scopes'];
|
||||
$this->defaultScope = $params['default_scope'];
|
||||
$this->keys = $params['keys'];
|
||||
}
|
||||
|
||||
/* AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
if (!isset($this->authorizationCodes[$code])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_merge(array(
|
||||
'authorization_code' => $code,
|
||||
), $this->authorizationCodes[$code]);
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
$this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setAuthorizationCodes($authorization_codes)
|
||||
{
|
||||
$this->authorizationCodes = $authorization_codes;
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
unset($this->authorizationCodes[$code]);
|
||||
}
|
||||
|
||||
/* UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
$userDetails = $this->getUserDetails($username);
|
||||
|
||||
return $userDetails && $userDetails['password'] && $userDetails['password'] === $password;
|
||||
}
|
||||
|
||||
public function setUser($username, $password, $firstName = null, $lastName = null)
|
||||
{
|
||||
$this->userCredentials[$username] = array(
|
||||
'password' => $password,
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
if (!isset($this->userCredentials[$username])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_merge(array(
|
||||
'user_id' => $username,
|
||||
'password' => null,
|
||||
'first_name' => null,
|
||||
'last_name' => null,
|
||||
), $this->userCredentials[$username]);
|
||||
}
|
||||
|
||||
/* UserClaimsInterface */
|
||||
public function getUserClaims($user_id, $claims)
|
||||
{
|
||||
if (!$userDetails = $this->getUserDetails($user_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$claims = explode(' ', trim($claims));
|
||||
$userClaims = array();
|
||||
|
||||
// for each requested claim, if the user has the claim, set it in the response
|
||||
$validClaims = explode(' ', self::VALID_CLAIMS);
|
||||
foreach ($validClaims as $validClaim) {
|
||||
if (in_array($validClaim, $claims)) {
|
||||
if ($validClaim == 'address') {
|
||||
// address is an object with subfields
|
||||
$userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
|
||||
} else {
|
||||
$userClaims = array_merge($this->getUserClaim($validClaim, $userDetails));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
protected function getUserClaim($claim, $userDetails)
|
||||
{
|
||||
$userClaims = array();
|
||||
$claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
|
||||
$claimValues = explode(' ', $claimValuesString);
|
||||
|
||||
foreach ($claimValues as $value) {
|
||||
$userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
/* ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
return isset($this->clientCredentials[$client_id]['client_secret']) && $this->clientCredentials[$client_id]['client_secret'] === $client_secret;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
if (!isset($this->clientCredentials[$client_id])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($this->clientCredentials[$client_id]['client_secret']);
|
||||
}
|
||||
|
||||
/* ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
if (!isset($this->clientCredentials[$client_id])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$clientDetails = array_merge(array(
|
||||
'client_id' => $client_id,
|
||||
'client_secret' => null,
|
||||
'redirect_uri' => null,
|
||||
'scope' => null,
|
||||
), $this->clientCredentials[$client_id]);
|
||||
|
||||
return $clientDetails;
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
if (isset($this->clientCredentials[$client_id]['grant_types'])) {
|
||||
$grant_types = explode(' ', $this->clientCredentials[$client_id]['grant_types']);
|
||||
|
||||
return in_array($grant_type, $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
$this->clientCredentials[$client_id] = array(
|
||||
'client_id' => $client_id,
|
||||
'client_secret' => $client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_types' => $grant_types,
|
||||
'scope' => $scope,
|
||||
'user_id' => $user_id,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
return isset($this->refreshTokens[$refresh_token]) ? $this->refreshTokens[$refresh_token] : false;
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
$this->refreshTokens[$refresh_token] = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
unset($this->refreshTokens[$refresh_token]);
|
||||
}
|
||||
|
||||
public function setRefreshTokens($refresh_tokens)
|
||||
{
|
||||
$this->refreshTokens = $refresh_tokens;
|
||||
}
|
||||
|
||||
/* AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
return isset($this->accessTokens[$access_token]) ? $this->accessTokens[$access_token] : false;
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
$this->accessTokens[$access_token] = compact('access_token', 'client_id', 'user_id', 'expires', 'scope', 'id_token');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
unset($this->accessTokens[$access_token]);
|
||||
}
|
||||
|
||||
public function scopeExists($scope)
|
||||
{
|
||||
$scope = explode(' ', trim($scope));
|
||||
|
||||
return (count(array_diff($scope, $this->supportedScopes)) == 0);
|
||||
}
|
||||
|
||||
public function getDefaultScope($client_id = null)
|
||||
{
|
||||
return $this->defaultScope;
|
||||
}
|
||||
|
||||
/*JWTBearerInterface */
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
if (isset($this->jwt[$client_id])) {
|
||||
$jwt = $this->jwt[$client_id];
|
||||
if ($jwt) {
|
||||
if ($jwt["subject"] == $subject) {
|
||||
return $jwt["key"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
foreach ($this->jti as $storedJti) {
|
||||
if ($storedJti['issuer'] == $client_id && $storedJti['subject'] == $subject && $storedJti['audience'] == $audience && $storedJti['expires'] == $expires && $storedJti['jti'] == $jti) {
|
||||
return array(
|
||||
'issuer' => $storedJti['issuer'],
|
||||
'subject' => $storedJti['subject'],
|
||||
'audience' => $storedJti['audience'],
|
||||
'expires' => $storedJti['expires'],
|
||||
'jti' => $storedJti['jti']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
$this->jti[] = array('issuer' => $client_id, 'subject' => $subject, 'audience' => $audience, 'expires' => $expires, 'jti' => $jti);
|
||||
}
|
||||
|
||||
/*PublicKeyInterface */
|
||||
public function getPublicKey($client_id = null)
|
||||
{
|
||||
if (isset($this->keys[$client_id])) {
|
||||
return $this->keys[$client_id]['public_key'];
|
||||
}
|
||||
|
||||
// use a global encryption pair
|
||||
if (isset($this->keys['public_key'])) {
|
||||
return $this->keys['public_key'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getPrivateKey($client_id = null)
|
||||
{
|
||||
if (isset($this->keys[$client_id])) {
|
||||
return $this->keys[$client_id]['private_key'];
|
||||
}
|
||||
|
||||
// use a global encryption pair
|
||||
if (isset($this->keys['private_key'])) {
|
||||
return $this->keys['private_key'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getEncryptionAlgorithm($client_id = null)
|
||||
{
|
||||
if (isset($this->keys[$client_id]['encryption_algorithm'])) {
|
||||
return $this->keys[$client_id]['encryption_algorithm'];
|
||||
}
|
||||
|
||||
// use a global encryption algorithm
|
||||
if (isset($this->keys['encryption_algorithm'])) {
|
||||
return $this->keys['encryption_algorithm'];
|
||||
}
|
||||
|
||||
return 'RS256';
|
||||
}
|
||||
}
|
333
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php
vendored
Normal file
333
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Mongo.php
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
* Simple MongoDB storage for all storage types
|
||||
*
|
||||
* NOTE: This class is meant to get users started
|
||||
* quickly. If your application requires further
|
||||
* customization, extend this class or create your own.
|
||||
*
|
||||
* NOTE: Passwords are stored in plaintext, which is never
|
||||
* a good idea. Be sure to override this for your application
|
||||
*
|
||||
* @author Julien Chaumond <chaumond@gmail.com>
|
||||
*/
|
||||
class Mongo implements AuthorizationCodeInterface,
|
||||
AccessTokenInterface,
|
||||
ClientCredentialsInterface,
|
||||
UserCredentialsInterface,
|
||||
RefreshTokenInterface,
|
||||
JwtBearerInterface,
|
||||
OpenIDAuthorizationCodeInterface
|
||||
{
|
||||
protected $db;
|
||||
protected $config;
|
||||
|
||||
public function __construct($connection, $config = array())
|
||||
{
|
||||
if ($connection instanceof \MongoDB) {
|
||||
$this->db = $connection;
|
||||
} else {
|
||||
if (!is_array($connection)) {
|
||||
throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array');
|
||||
}
|
||||
$server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']);
|
||||
$m = new \MongoClient($server);
|
||||
$this->db = $m->{$connection['database']};
|
||||
}
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'client_table' => 'oauth_clients',
|
||||
'access_token_table' => 'oauth_access_tokens',
|
||||
'refresh_token_table' => 'oauth_refresh_tokens',
|
||||
'code_table' => 'oauth_authorization_codes',
|
||||
'user_table' => 'oauth_users',
|
||||
'jwt_table' => 'oauth_jwt',
|
||||
), $config);
|
||||
}
|
||||
|
||||
// Helper function to access a MongoDB collection by `type`:
|
||||
protected function collection($name)
|
||||
{
|
||||
return $this->db->{$this->config[$name]};
|
||||
}
|
||||
|
||||
/* ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
|
||||
return $result['client_secret'] == $client_secret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($result['client_secret']);
|
||||
}
|
||||
|
||||
/* ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
$result = $this->collection('client_table')->findOne(array('client_id' => $client_id));
|
||||
|
||||
return is_null($result) ? false : $result;
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
if ($this->getClientDetails($client_id)) {
|
||||
$this->collection('client_table')->update(
|
||||
array('client_id' => $client_id),
|
||||
array('$set' => array(
|
||||
'client_secret' => $client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_types' => $grant_types,
|
||||
'scope' => $scope,
|
||||
'user_id' => $user_id,
|
||||
))
|
||||
);
|
||||
} else {
|
||||
$client = array(
|
||||
'client_id' => $client_id,
|
||||
'client_secret' => $client_secret,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'grant_types' => $grant_types,
|
||||
'scope' => $scope,
|
||||
'user_id' => $user_id,
|
||||
);
|
||||
$this->collection('client_table')->insert($client);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
$details = $this->getClientDetails($client_id);
|
||||
if (isset($details['grant_types'])) {
|
||||
$grant_types = explode(' ', $details['grant_types']);
|
||||
|
||||
return in_array($grant_type, $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
/* AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
$token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token));
|
||||
|
||||
return is_null($token) ? false : $token;
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
// if it exists, update it.
|
||||
if ($this->getAccessToken($access_token)) {
|
||||
$this->collection('access_token_table')->update(
|
||||
array('access_token' => $access_token),
|
||||
array('$set' => array(
|
||||
'client_id' => $client_id,
|
||||
'expires' => $expires,
|
||||
'user_id' => $user_id,
|
||||
'scope' => $scope
|
||||
))
|
||||
);
|
||||
} else {
|
||||
$token = array(
|
||||
'access_token' => $access_token,
|
||||
'client_id' => $client_id,
|
||||
'expires' => $expires,
|
||||
'user_id' => $user_id,
|
||||
'scope' => $scope
|
||||
);
|
||||
$this->collection('access_token_table')->insert($token);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
$this->collection('access_token_table')->remove(array('access_token' => $access_token));
|
||||
}
|
||||
|
||||
|
||||
/* AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
$code = $this->collection('code_table')->findOne(array('authorization_code' => $code));
|
||||
|
||||
return is_null($code) ? false : $code;
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
// if it exists, update it.
|
||||
if ($this->getAuthorizationCode($code)) {
|
||||
$this->collection('code_table')->update(
|
||||
array('authorization_code' => $code),
|
||||
array('$set' => array(
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope,
|
||||
'id_token' => $id_token,
|
||||
))
|
||||
);
|
||||
} else {
|
||||
$token = array(
|
||||
'authorization_code' => $code,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope,
|
||||
'id_token' => $id_token,
|
||||
);
|
||||
$this->collection('code_table')->insert($token);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
$this->collection('code_table')->remove(array('authorization_code' => $code));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
return $this->checkPassword($user, $password);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
$user['user_id'] = $user['username'];
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/* RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
$token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token));
|
||||
|
||||
return is_null($token) ? false : $token;
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
$token = array(
|
||||
'refresh_token' => $refresh_token,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope
|
||||
);
|
||||
$this->collection('refresh_token_table')->insert($token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
$this->collection('refresh_token_table')->remove(array('refresh_token' => $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->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.');
|
||||
}
|
||||
}
|
543
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php
vendored
Normal file
543
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php
vendored
Normal file
|
@ -0,0 +1,543 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
* Simple PDO storage for all storage types
|
||||
*
|
||||
* NOTE: This class is meant to get users started
|
||||
* quickly. If your application requires further
|
||||
* customization, extend this class or create your own.
|
||||
*
|
||||
* NOTE: Passwords are stored in plaintext, which is never
|
||||
* a good idea. Be sure to override this for your application
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
class Pdo implements
|
||||
AuthorizationCodeInterface,
|
||||
AccessTokenInterface,
|
||||
ClientCredentialsInterface,
|
||||
UserCredentialsInterface,
|
||||
RefreshTokenInterface,
|
||||
JwtBearerInterface,
|
||||
ScopeInterface,
|
||||
PublicKeyInterface,
|
||||
UserClaimsInterface,
|
||||
OpenIDAuthorizationCodeInterface
|
||||
{
|
||||
protected $db;
|
||||
protected $config;
|
||||
|
||||
public function __construct($connection, $config = array())
|
||||
{
|
||||
if (!$connection instanceof \PDO) {
|
||||
if (is_string($connection)) {
|
||||
$connection = array('dsn' => $connection);
|
||||
}
|
||||
if (!is_array($connection)) {
|
||||
throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO, a DSN string, or a configuration array');
|
||||
}
|
||||
if (!isset($connection['dsn'])) {
|
||||
throw new \InvalidArgumentException('configuration array must contain "dsn"');
|
||||
}
|
||||
// merge optional parameters
|
||||
$connection = array_merge(array(
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
'options' => array(),
|
||||
), $connection);
|
||||
$connection = new \PDO($connection['dsn'], $connection['username'], $connection['password'], $connection['options']);
|
||||
}
|
||||
$this->db = $connection;
|
||||
|
||||
// debugging
|
||||
$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$this->config = array_merge(array(
|
||||
'client_table' => 'oauth_clients',
|
||||
'access_token_table' => 'oauth_access_tokens',
|
||||
'refresh_token_table' => 'oauth_refresh_tokens',
|
||||
'code_table' => 'oauth_authorization_codes',
|
||||
'user_table' => 'oauth_users',
|
||||
'jwt_table' => 'oauth_jwt',
|
||||
'jti_table' => 'oauth_jti',
|
||||
'scope_table' => 'oauth_scopes',
|
||||
'public_key_table' => 'oauth_public_keys',
|
||||
), $config);
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
|
||||
$stmt->execute(compact('client_id'));
|
||||
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
// make this extensible
|
||||
return $result && $result['client_secret'] == $client_secret;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
|
||||
$stmt->execute(compact('client_id'));
|
||||
|
||||
if (!$result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($result['client_secret']);
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
|
||||
$stmt->execute(compact('client_id'));
|
||||
|
||||
return $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
// if it exists, update it.
|
||||
if ($this->getClientDetails($client_id)) {
|
||||
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id where client_id=:client_id', $this->config['client_table']));
|
||||
} else {
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (client_id, client_secret, redirect_uri, grant_types, scope, user_id) VALUES (:client_id, :client_secret, :redirect_uri, :grant_types, :scope, :user_id)', $this->config['client_table']));
|
||||
}
|
||||
|
||||
return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'));
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
$details = $this->getClientDetails($client_id);
|
||||
if (isset($details['grant_types'])) {
|
||||
$grant_types = explode(' ', $details['grant_types']);
|
||||
|
||||
return in_array($grant_type, (array) $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table']));
|
||||
|
||||
$token = $stmt->execute(compact('access_token'));
|
||||
if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
// convert date string back to timestamp
|
||||
$token['expires'] = strtotime($token['expires']);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
// convert expires to datestring
|
||||
$expires = date('Y-m-d H:i:s', $expires);
|
||||
|
||||
// if it exists, update it.
|
||||
if ($this->getAccessToken($access_token)) {
|
||||
$stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['access_token_table']));
|
||||
} else {
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table']));
|
||||
}
|
||||
|
||||
return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope'));
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table']));
|
||||
|
||||
return $stmt->execute(compact('access_token'));
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table']));
|
||||
$stmt->execute(compact('code'));
|
||||
|
||||
if ($code = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
// convert date string back to timestamp
|
||||
$code['expires'] = strtotime($code['expires']);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
if (func_num_args() > 6) {
|
||||
// we are calling with an id token
|
||||
return call_user_func_array(array($this, 'setAuthorizationCodeWithIdToken'), func_get_args());
|
||||
}
|
||||
|
||||
// convert expires to datestring
|
||||
$expires = date('Y-m-d H:i:s', $expires);
|
||||
|
||||
// if it exists, update it.
|
||||
if ($this->getAuthorizationCode($code)) {
|
||||
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table']));
|
||||
} else {
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table']));
|
||||
}
|
||||
|
||||
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
|
||||
}
|
||||
|
||||
private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
// convert expires to datestring
|
||||
$expires = date('Y-m-d H:i:s', $expires);
|
||||
|
||||
// if it exists, update it.
|
||||
if ($this->getAuthorizationCode($code)) {
|
||||
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table']));
|
||||
} else {
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table']));
|
||||
}
|
||||
|
||||
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table']));
|
||||
|
||||
return $stmt->execute(compact('code'));
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
if ($user = $this->getUser($username)) {
|
||||
return $this->checkPassword($user, $password);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
return $this->getUser($username);
|
||||
}
|
||||
|
||||
/* UserClaimsInterface */
|
||||
public function getUserClaims($user_id, $claims)
|
||||
{
|
||||
if (!$userDetails = $this->getUserDetails($user_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$claims = explode(' ', trim($claims));
|
||||
$userClaims = array();
|
||||
|
||||
// for each requested claim, if the user has the claim, set it in the response
|
||||
$validClaims = explode(' ', self::VALID_CLAIMS);
|
||||
foreach ($validClaims as $validClaim) {
|
||||
if (in_array($validClaim, $claims)) {
|
||||
if ($validClaim == 'address') {
|
||||
// address is an object with subfields
|
||||
$userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
|
||||
} else {
|
||||
$userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
protected function getUserClaim($claim, $userDetails)
|
||||
{
|
||||
$userClaims = array();
|
||||
$claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
|
||||
$claimValues = explode(' ', $claimValuesString);
|
||||
|
||||
foreach ($claimValues as $value) {
|
||||
$userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
|
||||
}
|
||||
|
||||
return $userClaims;
|
||||
}
|
||||
|
||||
/* OAuth2\Storage\RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
|
||||
|
||||
$token = $stmt->execute(compact('refresh_token'));
|
||||
if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
// convert expires to epoch time
|
||||
$token['expires'] = strtotime($token['expires']);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
// convert expires to datestring
|
||||
$expires = date('Y-m-d H:i:s', $expires);
|
||||
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (refresh_token, client_id, user_id, expires, scope) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table']));
|
||||
|
||||
return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'));
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
|
||||
|
||||
return $stmt->execute(compact('refresh_token'));
|
||||
}
|
||||
|
||||
// plaintext passwords are bad! Override this for your application
|
||||
protected function checkPassword($user, $password)
|
||||
{
|
||||
return $user['password'] == sha1($password);
|
||||
}
|
||||
|
||||
public function getUser($username)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table']));
|
||||
$stmt->execute(array('username' => $username));
|
||||
|
||||
if (!$userInfo = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the default behavior is to use "username" as the user_id
|
||||
return array_merge(array(
|
||||
'user_id' => $username
|
||||
), $userInfo);
|
||||
}
|
||||
|
||||
public function setUser($username, $password, $firstName = null, $lastName = null)
|
||||
{
|
||||
// do not store in plaintext
|
||||
$password = sha1($password);
|
||||
|
||||
// if it exists, update it.
|
||||
if ($this->getUser($username)) {
|
||||
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table']));
|
||||
} else {
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table']));
|
||||
}
|
||||
|
||||
return $stmt->execute(compact('username', 'password', 'firstName', 'lastName'));
|
||||
}
|
||||
|
||||
/* ScopeInterface */
|
||||
public function scopeExists($scope)
|
||||
{
|
||||
$scope = explode(' ', $scope);
|
||||
$whereIn = implode(',', array_fill(0, count($scope), '?'));
|
||||
$stmt = $this->db->prepare(sprintf('SELECT count(scope) as count FROM %s WHERE scope IN (%s)', $this->config['scope_table'], $whereIn));
|
||||
$stmt->execute($scope);
|
||||
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return $result['count'] == count($scope);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDefaultScope($client_id = null)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table']));
|
||||
$stmt->execute(array('is_default' => true));
|
||||
|
||||
if ($result = $stmt->fetchAll(\PDO::FETCH_ASSOC)) {
|
||||
$defaultScope = array_map(function ($row) {
|
||||
return $row['scope'];
|
||||
}, $result);
|
||||
|
||||
return implode(' ', $defaultScope);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* JWTBearerInterface */
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table']));
|
||||
|
||||
$stmt->execute(array('client_id' => $client_id, 'subject' => $subject));
|
||||
|
||||
return $stmt->fetchColumn();
|
||||
}
|
||||
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table']));
|
||||
|
||||
$stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
|
||||
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return array(
|
||||
'issuer' => $result['issuer'],
|
||||
'subject' => $result['subject'],
|
||||
'audience' => $result['audience'],
|
||||
'expires' => $result['expires'],
|
||||
'jti' => $result['jti'],
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expires, $jti)
|
||||
{
|
||||
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table']));
|
||||
|
||||
return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
|
||||
}
|
||||
|
||||
/* PublicKeyInterface */
|
||||
public function getPublicKey($client_id = null)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
|
||||
|
||||
$stmt->execute(compact('client_id'));
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return $result['public_key'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrivateKey($client_id = null)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
|
||||
|
||||
$stmt->execute(compact('client_id'));
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return $result['private_key'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getEncryptionAlgorithm($client_id = null)
|
||||
{
|
||||
$stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
|
||||
|
||||
$stmt->execute(compact('client_id'));
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return $result['encryption_algorithm'];
|
||||
}
|
||||
|
||||
return 'RS256';
|
||||
}
|
||||
|
||||
/**
|
||||
* DDL to create OAuth2 database and tables for PDO storage
|
||||
*
|
||||
* @see https://github.com/dsquier/oauth2-server-php-mysql
|
||||
*/
|
||||
public function getBuildSql($dbName = 'oauth2_server_php')
|
||||
{
|
||||
$sql = "
|
||||
CREATE TABLE {$this->config['client_table']} (
|
||||
client_id VARCHAR(80) NOT NULL,
|
||||
client_secret VARCHAR(80) 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['jti_table']} (
|
||||
issuer VARCHAR(80) NOT NULL,
|
||||
subject VARCHAR(80),
|
||||
audiance VARCHAR(80),
|
||||
expires TIMESTAMP NOT NULL,
|
||||
jti VARCHAR(2000) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE {$this->config['public_key_table']} (
|
||||
client_id VARCHAR(80),
|
||||
public_key VARCHAR(2000),
|
||||
private_key VARCHAR(2000),
|
||||
encryption_algorithm VARCHAR(100) DEFAULT 'RS256'
|
||||
)
|
||||
";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php
vendored
Normal file
16
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/PublicKeyInterface.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get public/private key information
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface PublicKeyInterface
|
||||
{
|
||||
public function getPublicKey($client_id = null);
|
||||
public function getPrivateKey($client_id = null);
|
||||
public function getEncryptionAlgorithm($client_id = null);
|
||||
}
|
317
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php
vendored
Normal file
317
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Redis.php
vendored
Normal file
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
|
||||
/**
|
||||
* redis storage for all storage types
|
||||
*
|
||||
* To use, install "predis/predis" via composer
|
||||
*
|
||||
* Register client:
|
||||
* <code>
|
||||
* $storage = new OAuth2\Storage\Redis($redis);
|
||||
* $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
|
||||
* </code>
|
||||
*/
|
||||
class Redis implements AuthorizationCodeInterface,
|
||||
AccessTokenInterface,
|
||||
ClientCredentialsInterface,
|
||||
UserCredentialsInterface,
|
||||
RefreshTokenInterface,
|
||||
JwtBearerInterface,
|
||||
ScopeInterface,
|
||||
OpenIDAuthorizationCodeInterface
|
||||
{
|
||||
|
||||
private $cache;
|
||||
|
||||
/* The redis client */
|
||||
protected $redis;
|
||||
|
||||
/* Configuration array */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Redis Storage!
|
||||
*
|
||||
* @param \Predis\Client $redis
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($redis, $config=array())
|
||||
{
|
||||
$this->redis = $redis;
|
||||
$this->config = array_merge(array(
|
||||
'client_key' => 'oauth_clients:',
|
||||
'access_token_key' => 'oauth_access_tokens:',
|
||||
'refresh_token_key' => 'oauth_refresh_tokens:',
|
||||
'code_key' => 'oauth_authorization_codes:',
|
||||
'user_key' => 'oauth_users:',
|
||||
'jwt_key' => 'oauth_jwt:',
|
||||
'scope_key' => 'oauth_scopes:',
|
||||
), $config);
|
||||
}
|
||||
|
||||
protected function getValue($key)
|
||||
{
|
||||
if ( isset($this->cache[$key]) ) {
|
||||
return $this->cache[$key];
|
||||
}
|
||||
$value = $this->redis->get($key);
|
||||
if ( isset($value) ) {
|
||||
return json_decode($value, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setValue($key, $value, $expire=0)
|
||||
{
|
||||
$this->cache[$key] = $value;
|
||||
$str = json_encode($value);
|
||||
if ($expire > 0) {
|
||||
$seconds = $expire - time();
|
||||
$ret = $this->redis->setex($key, $seconds, $str);
|
||||
} else {
|
||||
$ret = $this->redis->set($key, $str);
|
||||
}
|
||||
|
||||
// check that the key was set properly
|
||||
// if this fails, an exception will usually thrown, so this step isn't strictly necessary
|
||||
return is_bool($ret) ? $ret : $ret->getPayload() == 'OK';
|
||||
}
|
||||
|
||||
protected function expireValue($key)
|
||||
{
|
||||
unset($this->cache[$key]);
|
||||
|
||||
return $this->redis->del($key);
|
||||
}
|
||||
|
||||
/* AuthorizationCodeInterface */
|
||||
public function getAuthorizationCode($code)
|
||||
{
|
||||
return $this->getValue($this->config['code_key'] . $code);
|
||||
}
|
||||
|
||||
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['code_key'] . $authorization_code,
|
||||
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function expireAuthorizationCode($code)
|
||||
{
|
||||
$key = $this->config['code_key'] . $code;
|
||||
unset($this->cache[$key]);
|
||||
|
||||
return $this->expireValue($key);
|
||||
}
|
||||
|
||||
/* UserCredentialsInterface */
|
||||
public function checkUserCredentials($username, $password)
|
||||
{
|
||||
$user = $this->getUserDetails($username);
|
||||
|
||||
return $user && $user['password'] === $password;
|
||||
}
|
||||
|
||||
public function getUserDetails($username)
|
||||
{
|
||||
return $this->getUser($username);
|
||||
}
|
||||
|
||||
public function getUser($username)
|
||||
{
|
||||
if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the default behavior is to use "username" as the user_id
|
||||
return array_merge(array(
|
||||
'user_id' => $username,
|
||||
), $userInfo);
|
||||
}
|
||||
|
||||
public function setUser($username, $password, $first_name = null, $last_name = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['user_key'] . $username,
|
||||
compact('username', 'password', 'first_name', 'last_name')
|
||||
);
|
||||
}
|
||||
|
||||
/* ClientCredentialsInterface */
|
||||
public function checkClientCredentials($client_id, $client_secret = null)
|
||||
{
|
||||
if (!$client = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset($client['client_secret'])
|
||||
&& $client['client_secret'] == $client_secret;
|
||||
}
|
||||
|
||||
public function isPublicClient($client_id)
|
||||
{
|
||||
if (!$client = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return empty($result['client_secret']);
|
||||
}
|
||||
|
||||
/* ClientInterface */
|
||||
public function getClientDetails($client_id)
|
||||
{
|
||||
return $this->getValue($this->config['client_key'] . $client_id);
|
||||
}
|
||||
|
||||
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['client_key'] . $client_id,
|
||||
compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')
|
||||
);
|
||||
}
|
||||
|
||||
public function checkRestrictedGrantType($client_id, $grant_type)
|
||||
{
|
||||
$details = $this->getClientDetails($client_id);
|
||||
if (isset($details['grant_types'])) {
|
||||
$grant_types = explode(' ', $details['grant_types']);
|
||||
|
||||
return in_array($grant_type, (array) $grant_types);
|
||||
}
|
||||
|
||||
// if grant_types are not defined, then none are restricted
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RefreshTokenInterface */
|
||||
public function getRefreshToken($refresh_token)
|
||||
{
|
||||
return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
|
||||
}
|
||||
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['refresh_token_key'] . $refresh_token,
|
||||
compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function unsetRefreshToken($refresh_token)
|
||||
{
|
||||
return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
|
||||
}
|
||||
|
||||
/* AccessTokenInterface */
|
||||
public function getAccessToken($access_token)
|
||||
{
|
||||
return $this->getValue($this->config['access_token_key'].$access_token);
|
||||
}
|
||||
|
||||
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
|
||||
{
|
||||
return $this->setValue(
|
||||
$this->config['access_token_key'].$access_token,
|
||||
compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
|
||||
$expires
|
||||
);
|
||||
}
|
||||
|
||||
public function unsetAccessToken($access_token)
|
||||
{
|
||||
return $this->expireValue($this->config['access_token_key'] . $access_token);
|
||||
}
|
||||
|
||||
/* ScopeInterface */
|
||||
public function scopeExists($scope)
|
||||
{
|
||||
$scope = explode(' ', $scope);
|
||||
|
||||
$result = $this->getValue($this->config['scope_key'].'supported:global');
|
||||
|
||||
$supportedScope = explode(' ', (string) $result);
|
||||
|
||||
return (count(array_diff($scope, $supportedScope)) == 0);
|
||||
}
|
||||
|
||||
public function getDefaultScope($client_id = null)
|
||||
{
|
||||
if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
|
||||
$result = $this->getValue($this->config['scope_key'].'default:global');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function setScope($scope, $client_id = null, $type = 'supported')
|
||||
{
|
||||
if (!in_array($type, array('default', 'supported'))) {
|
||||
throw new \InvalidArgumentException('"$type" must be one of "default", "supported"');
|
||||
}
|
||||
|
||||
if (is_null($client_id)) {
|
||||
$key = $this->config['scope_key'].$type.':global';
|
||||
} else {
|
||||
$key = $this->config['scope_key'].$type.':'.$client_id;
|
||||
}
|
||||
|
||||
return $this->setValue($key, $scope);
|
||||
}
|
||||
|
||||
/*JWTBearerInterface */
|
||||
public function getClientKey($client_id, $subject)
|
||||
{
|
||||
if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
|
||||
return $jwt['key'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setClientKey($client_id, $key, $subject = null)
|
||||
{
|
||||
return $this->setValue($this->config['jwt_key'] . $client_id, array(
|
||||
'key' => $key,
|
||||
'subject' => $subject
|
||||
));
|
||||
}
|
||||
|
||||
public function getClientScope($client_id)
|
||||
{
|
||||
if (!$clientDetails = $this->getClientDetails($client_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($clientDetails['scope'])) {
|
||||
return $clientDetails['scope'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs redis implementation.
|
||||
throw new \Exception('getJti() for the Redis driver is currently unimplemented.');
|
||||
}
|
||||
|
||||
public function setJti($client_id, $subject, $audience, $expiration, $jti)
|
||||
{
|
||||
//TODO: Needs redis implementation.
|
||||
throw new \Exception('setJti() for the Redis driver is currently unimplemented.');
|
||||
}
|
||||
}
|
82
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php
vendored
Normal file
82
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/RefreshTokenInterface.php
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should get/save refresh tokens for the "Refresh Token"
|
||||
* grant type
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface RefreshTokenInterface
|
||||
{
|
||||
/**
|
||||
* Grant refresh access tokens.
|
||||
*
|
||||
* Retrieve the stored data for the given refresh token.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN.
|
||||
*
|
||||
* @param $refresh_token
|
||||
* Refresh token to be check with.
|
||||
*
|
||||
* @return
|
||||
* An associative array as below, and NULL if the refresh_token is
|
||||
* invalid:
|
||||
* - refresh_token: Refresh token identifier.
|
||||
* - client_id: Client identifier.
|
||||
* - user_id: User identifier.
|
||||
* - expires: Expiration unix timestamp, or 0 if the token doesn't expire.
|
||||
* - scope: (optional) Scope values in space-separated string.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-6
|
||||
*
|
||||
* @ingroup oauth2_section_6
|
||||
*/
|
||||
public function getRefreshToken($refresh_token);
|
||||
|
||||
/**
|
||||
* Take the provided refresh token values and store them somewhere.
|
||||
*
|
||||
* This function should be the storage counterpart to getRefreshToken().
|
||||
*
|
||||
* If storage fails for some reason, we're not currently checking for
|
||||
* any sort of success/failure, so you should bail out of the script
|
||||
* and provide a descriptive fail message.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN.
|
||||
*
|
||||
* @param $refresh_token
|
||||
* Refresh token to be stored.
|
||||
* @param $client_id
|
||||
* Client identifier to be stored.
|
||||
* @param $user_id
|
||||
* User identifier to be stored.
|
||||
* @param $expires
|
||||
* Expiration timestamp to be stored. 0 if the token doesn't expire.
|
||||
* @param $scope
|
||||
* (optional) Scopes to be stored in space-separated string.
|
||||
*
|
||||
* @ingroup oauth2_section_6
|
||||
*/
|
||||
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null);
|
||||
|
||||
/**
|
||||
* Expire a used refresh token.
|
||||
*
|
||||
* This is not explicitly required in the spec, but is almost implied.
|
||||
* After granting a new refresh token, the old one is no longer useful and
|
||||
* so should be forcibly expired in the data store so it can't be used again.
|
||||
*
|
||||
* If storage fails for some reason, we're not currently checking for
|
||||
* any sort of success/failure, so you should bail out of the script
|
||||
* and provide a descriptive fail message.
|
||||
*
|
||||
* @param $refresh_token
|
||||
* Refresh token to be expirse.
|
||||
*
|
||||
* @ingroup oauth2_section_6
|
||||
*/
|
||||
public function unsetRefreshToken($refresh_token);
|
||||
}
|
46
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php
vendored
Normal file
46
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should retrieve data involving the relevent scopes associated
|
||||
* with this implementation.
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface ScopeInterface
|
||||
{
|
||||
/**
|
||||
* Check if the provided scope exists.
|
||||
*
|
||||
* @param $scope
|
||||
* A space-separated string of scopes.
|
||||
*
|
||||
* @return
|
||||
* TRUE if it exists, FALSE otherwise.
|
||||
*/
|
||||
public function scopeExists($scope);
|
||||
|
||||
/**
|
||||
* The default scope to use in the event the client
|
||||
* does not request one. By returning "false", a
|
||||
* request_error is returned by the server to force a
|
||||
* scope request by the client. By returning "null",
|
||||
* opt out of requiring scopes
|
||||
*
|
||||
* @param $client_id
|
||||
* An optional client id that can be used to return customized default scopes.
|
||||
*
|
||||
* @return
|
||||
* string representation of default scope, null if
|
||||
* scopes are not defined, or false to force scope
|
||||
* request by the client
|
||||
*
|
||||
* ex:
|
||||
* 'default'
|
||||
* ex:
|
||||
* null
|
||||
*/
|
||||
public function getDefaultScope($client_id = null);
|
||||
}
|
52
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php
vendored
Normal file
52
vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/UserCredentialsInterface.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\Storage;
|
||||
|
||||
/**
|
||||
* Implement this interface to specify where the OAuth2 Server
|
||||
* should retrieve user credentials for the
|
||||
* "Resource Owner Password Credentials" grant type
|
||||
*
|
||||
* @author Brent Shaffer <bshafs at gmail dot com>
|
||||
*/
|
||||
interface UserCredentialsInterface
|
||||
{
|
||||
/**
|
||||
* Grant access tokens for basic user credentials.
|
||||
*
|
||||
* Check the supplied username and password for validity.
|
||||
*
|
||||
* You can also use the $client_id param to do any checks required based
|
||||
* on a client, if you need that.
|
||||
*
|
||||
* Required for OAuth2::GRANT_TYPE_USER_CREDENTIALS.
|
||||
*
|
||||
* @param $username
|
||||
* Username to be check with.
|
||||
* @param $password
|
||||
* Password to be check with.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the username and password are valid, and FALSE if it isn't.
|
||||
* Moreover, if the username and password are valid, and you want to
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6749#section-4.3
|
||||
*
|
||||
* @ingroup oauth2_section_4
|
||||
*/
|
||||
public function checkUserCredentials($username, $password);
|
||||
|
||||
/**
|
||||
* @return
|
||||
* ARRAY the associated "user_id" and optional "scope" values
|
||||
* This function MUST return FALSE if the requested user does not exist or is
|
||||
* invalid. "scope" is a space-separated list of restricted scopes.
|
||||
* @code
|
||||
* return array(
|
||||
* "user_id" => USER_ID, // REQUIRED user_id to be stored with the authorization code or access token
|
||||
* "scope" => SCOPE // OPTIONAL space-separated list of restricted scopes
|
||||
* );
|
||||
* @endcode
|
||||
*/
|
||||
public function getUserDetails($username);
|
||||
}
|
130
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php
vendored
Normal file
130
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\TokenType;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Bearer implements TokenTypeInterface
|
||||
{
|
||||
private $config;
|
||||
|
||||
public function __construct(array $config = array())
|
||||
{
|
||||
$this->config = array_merge(array(
|
||||
'token_param_name' => 'access_token',
|
||||
'token_bearer_header_name' => 'Bearer',
|
||||
), $config);
|
||||
}
|
||||
|
||||
public function getTokenType()
|
||||
{
|
||||
return 'Bearer';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request has supplied token
|
||||
*
|
||||
* @see https://github.com/bshaffer/oauth2-server-php/issues/349#issuecomment-37993588
|
||||
*/
|
||||
public function requestHasToken(RequestInterface $request)
|
||||
{
|
||||
$headers = $request->headers('AUTHORIZATION');
|
||||
|
||||
// check the header, then the querystring, then the request body
|
||||
return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name']));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience function that can be used to get the token, which can then
|
||||
* be passed to getAccessTokenData(). The constraints specified by the draft are
|
||||
* attempted to be adheared to in this method.
|
||||
*
|
||||
* As per the Bearer spec (draft 8, section 2) - there are three ways for a client
|
||||
* to specify the bearer token, in order of preference: Authorization Header,
|
||||
* POST and GET.
|
||||
*
|
||||
* NB: Resource servers MUST accept tokens via the Authorization scheme
|
||||
* (http://tools.ietf.org/html/rfc6750#section-2).
|
||||
*
|
||||
* @todo Should we enforce TLS/SSL in this function?
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-2.1
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-2.2
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-2.3
|
||||
*
|
||||
* Old Android version bug (at least with version 2.2)
|
||||
* @see http://code.google.com/p/android/issues/detail?id=6684
|
||||
*
|
||||
*/
|
||||
public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$headers = $request->headers('AUTHORIZATION');
|
||||
|
||||
/**
|
||||
* Ensure more than one method is not used for including an
|
||||
* access token
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-3.1
|
||||
*/
|
||||
$methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name']));
|
||||
if ($methodsUsed > 1) {
|
||||
$response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no authentication is provided, set the status code
|
||||
* to 401 and return no other error information
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6750#section-3.1
|
||||
*/
|
||||
if ($methodsUsed == 0) {
|
||||
$response->setStatusCode(401);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// HEADER: Get the access token from the header
|
||||
if (!empty($headers)) {
|
||||
if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\s(\S+)/i', $headers, $matches)) {
|
||||
$response->setError(400, 'invalid_request', 'Malformed auth header');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
if ($request->request($this->config['token_param_name'])) {
|
||||
// // POST: Get the token from POST data
|
||||
if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) {
|
||||
$response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$contentType = $request->server('CONTENT_TYPE');
|
||||
if (false !== $pos = strpos($contentType, ';')) {
|
||||
$contentType = substr($contentType, 0, $pos);
|
||||
}
|
||||
|
||||
if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') {
|
||||
// IETF specifies content-type. NB: Not all webservers populate this _SERVER variable
|
||||
// @see http://tools.ietf.org/html/rfc6750#section-2.2
|
||||
$response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $request->request($this->config['token_param_name']);
|
||||
}
|
||||
|
||||
// GET method
|
||||
return $request->query($this->config['token_param_name']);
|
||||
}
|
||||
}
|
22
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php
vendored
Normal file
22
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\TokenType;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
/**
|
||||
* This is not yet supported!
|
||||
*/
|
||||
class Mac implements TokenTypeInterface
|
||||
{
|
||||
public function getTokenType()
|
||||
{
|
||||
return 'mac';
|
||||
}
|
||||
|
||||
public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
throw new \LogicException("Not supported");
|
||||
}
|
||||
}
|
21
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php
vendored
Normal file
21
vendor/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace OAuth2\TokenType;
|
||||
|
||||
use OAuth2\RequestInterface;
|
||||
use OAuth2\ResponseInterface;
|
||||
|
||||
interface TokenTypeInterface
|
||||
{
|
||||
/**
|
||||
* Token type identification string
|
||||
*
|
||||
* ex: "bearer" or "mac"
|
||||
*/
|
||||
public function getTokenType();
|
||||
|
||||
/**
|
||||
* Retrieves the token string from the request object
|
||||
*/
|
||||
public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response);
|
||||
}
|
Reference in a new issue