fix conflicts

This commit is contained in:
Julián Gutiérrez 2016-01-17 15:49:55 +01:00
commit 4862ca7d60
16 changed files with 361 additions and 252 deletions

View File

@ -148,7 +148,7 @@
"dist": { "dist": {
"type": "path", "type": "path",
"url": "../", "url": "../",
"reference": "dce1620f60d9f1a44a9ec99b6168810a8030c20c", "reference": "168e7640c6e8217b7e961151de522810b3edce6e",
"shasum": null "shasum": null
}, },
"require": { "require": {

View File

@ -14,19 +14,33 @@ use Slim\Http\Response;
include(__DIR__ . '/../vendor/autoload.php'); include(__DIR__ . '/../vendor/autoload.php');
// Setup the authorization server
$server = new Server('file://' . __DIR__ . '/../private.key');
// Init our repositories
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
// Enable the client credentials grant on the server
$server->enableGrantType(new ClientCredentialsGrant($clientRepository, $scopeRepository, $accessTokenRepository));
// App // App
$app = new App([Server::class => $server]); $app = new App([
Server::class => function () {
// Init our repositories
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
// Setup the authorization server
$server = new Server(
$clientRepository,
$accessTokenRepository,
$scopeRepository,
$privateKeyPath,
$publicKeyPath
);
// Enable the client credentials grant on the server with a token TTL of 1 hour
$server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1H'));
return $server;
}
]);
$app->post('/access_token', function (Request $request, Response $response) { $app->post('/access_token', function (Request $request, Response $response) {
/** @var Server $server */ /** @var Server $server */

View File

@ -16,28 +16,38 @@ use Slim\Http\Response;
include(__DIR__ . '/../vendor/autoload.php'); include(__DIR__ . '/../vendor/autoload.php');
// Setup the authorization server
$server = new Server('file://' . __DIR__ . '/../private.key');
// Init our repositories
$userRepository = new UserRepository();
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
$refreshTokenRepository = new RefreshTokenRepository();
// Enable the client credentials grant on the server
$passwordGrant = new PasswordGrant(
$userRepository,
$clientRepository,
$scopeRepository,
$accessTokenRepository,
$refreshTokenRepository
);
$server->enableGrantType($passwordGrant);
// App // App
$app = new App([Server::class => $server]); $app = new App([
Server::class => function () {
// Init our repositories
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
$userRepository = new UserRepository();
$refreshTokenRepository = new RefreshTokenRepository();
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
// Setup the authorization server
$server = new Server(
$clientRepository,
$accessTokenRepository,
$scopeRepository,
$privateKeyPath,
$publicKeyPath
);
// Enable the client credentials grant on the server with a token TTL of 1 hour
$server->enableGrantType(
new PasswordGrant($userRepository, $refreshTokenRepository),
new \DateInterval('PT1H')
);
return $server;
}
]);
$app->post('/access_token', function (Request $request, Response $response) { $app->post('/access_token', function (Request $request, Response $response) {
/** @var Server $server */ /** @var Server $server */

View File

@ -8,7 +8,6 @@ use OAuth2ServerExamples\Repositories\AccessTokenRepository;
use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ClientRepository;
use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\ScopeRepository;
use OAuth2ServerExamples\Repositories\UserRepository;
use Slim\App; use Slim\App;
use Slim\Http\Request; use Slim\Http\Request;
@ -16,28 +15,33 @@ use Slim\Http\Response;
include(__DIR__ . '/../vendor/autoload.php'); include(__DIR__ . '/../vendor/autoload.php');
// Setup the authorization server
$server = new Server('file://' . __DIR__ . '/../private.key');
// Init our repositories
$userRepository = new UserRepository();
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
$refreshTokenRepository = new RefreshTokenRepository();
// Enable the client credentials grant on the server
$refreshTokenGrant = new RefreshTokenGrant(
'file://' . __DIR__ . '/../public.key',
$clientRepository,
$scopeRepository,
$accessTokenRepository,
$refreshTokenRepository
);
$server->enableGrantType($refreshTokenGrant);
// App // App
$app = new App([Server::class => $server]); $app = new App([Server::class => function () {
// Init our repositories
$clientRepository = new ClientRepository();
$scopeRepository = new ScopeRepository();
$accessTokenRepository = new AccessTokenRepository();
$refreshTokenRepository = new RefreshTokenRepository();
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
// Setup the authorization server
$server = new Server(
$clientRepository,
$accessTokenRepository,
$scopeRepository,
$privateKeyPath,
$publicKeyPath
);
// Enable the refresh token grant on the server
$server->enableGrantType(new RefreshTokenGrant($refreshTokenRepository), new \DateInterval('PT1H'));
return $server;
}]);
$app->post('/access_token', function (Request $request, Response $response) { $app->post('/access_token', function (Request $request, Response $response) {
/** @var Server $server */ /** @var Server $server */

View File

@ -1,36 +0,0 @@
<?php
/**
* OAuth 2.0 Access Denied Exception
*
* @package league/oauth2-server
* @author Alex Bilbie <hello@alexbilbie.com>
* @copyright Copyright (c) Alex Bilbie
* @license http://mit-license.org/
* @link https://github.com/thephpleague/oauth2-server
*/
namespace League\OAuth2\Server\Exception;
/**
* Exception class
*/
class AccessDeniedException extends OAuthException
{
/**
* {@inheritdoc}
*/
public $httpStatusCode = 401;
/**
* {@inheritdoc}
*/
public $errorType = 'access_denied';
/**
* {@inheritdoc}
*/
public function __construct()
{
parent::__construct('The resource owner or authorization server denied the request.');
}
}

View File

@ -191,6 +191,18 @@ class OAuthServerException extends \Exception
return new static('The refresh token is invalid.', 'invalid_request', 400, $hint); return new static('The refresh token is invalid.', 'invalid_request', 400, $hint);
} }
/**
* Access denied
*
* @param null|string $hint
*
* @return static
*/
public static function accessDenied($hint = null)
{
return new static('The server denied the request.', 401, $hint);
}
/** /**
* @return string * @return string
*/ */
@ -202,7 +214,9 @@ class OAuthServerException extends \Exception
/** /**
* Generate a HTTP response * Generate a HTTP response
* *
* @return ResponseInterface * @param \Psr\Http\Message\ResponseInterface $response
*
* @return \Psr\Http\Message\ResponseInterface
*/ */
public function generateHttpResponse(ResponseInterface $response = null) public function generateHttpResponse(ResponseInterface $response = null)
{ {
@ -266,6 +280,8 @@ class OAuthServerException extends \Exception
if ($authHeader !== []) { if ($authHeader !== []) {
if (strpos($authHeader[0], 'Bearer') === 0) { if (strpos($authHeader[0], 'Bearer') === 0) {
$authScheme = 'Bearer'; $authScheme = 'Bearer';
} elseif (strpos($authHeader[0], 'MAC') === 0) {
$authScheme = 'MAC';
} elseif (strpos($authHeader[0], 'Basic') === 0) { } elseif (strpos($authHeader[0], 'Basic') === 0) {
$authScheme = 'Basic'; $authScheme = 'Basic';
} }

View File

@ -29,6 +29,8 @@ use Psr\Http\Message\ServerRequestInterface;
*/ */
abstract class AbstractGrant implements GrantTypeInterface abstract class AbstractGrant implements GrantTypeInterface
{ {
const SCOPE_DELIMITER_STRING = ' ';
/** /**
* Grant identifier * Grant identifier
* *
@ -69,20 +71,63 @@ abstract class AbstractGrant implements GrantTypeInterface
protected $scopeRepository; protected $scopeRepository;
/** /**
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @var string
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
*/ */
public function __construct( protected $pathToPrivateKey;
ClientRepositoryInterface $clientRepository,
ScopeRepositoryInterface $scopeRepository, /**
AccessTokenRepositoryInterface $accessTokenRepository * @var string
) { */
protected $pathToPublicKey;
/**
* @param ClientRepositoryInterface $clientRepository
*/
public function setClientRepository(ClientRepositoryInterface $clientRepository)
{
$this->clientRepository = $clientRepository; $this->clientRepository = $clientRepository;
$this->scopeRepository = $scopeRepository; }
/**
* @param AccessTokenRepositoryInterface $accessTokenRepository
*/
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository)
{
$this->accessTokenRepository = $accessTokenRepository; $this->accessTokenRepository = $accessTokenRepository;
} }
/**
* @param ScopeRepositoryInterface $scopeRepository
*/
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository)
{
$this->scopeRepository = $scopeRepository;
}
/**
* @param string $pathToPrivateKey
*/
public function setPathToPrivateKey($pathToPrivateKey)
{
$this->pathToPrivateKey = $pathToPrivateKey;
}
/**
* @param string $pathToPublicKey
*/
public function setPathToPublicKey($pathToPublicKey)
{
$this->pathToPublicKey = $pathToPublicKey;
}
/**
* @inheritdoc
*/
public function setEmitter(EmitterInterface $emitter)
{
$this->emitter = $emitter;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -99,14 +144,6 @@ abstract class AbstractGrant implements GrantTypeInterface
return $this->respondsWith; return $this->respondsWith;
} }
/**
* @inheritdoc
*/
public function setEmitter(EmitterInterface $emitter)
{
$this->emitter = $emitter;
}
/** /**
* @param \Psr\Http\Message\ServerRequestInterface $request * @param \Psr\Http\Message\ServerRequestInterface $request
* *
@ -152,7 +189,6 @@ abstract class AbstractGrant implements GrantTypeInterface
/** /**
* @param \Psr\Http\Message\ServerRequestInterface $request * @param \Psr\Http\Message\ServerRequestInterface $request
* @param string $scopeDelimiterString
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $redirectUri * @param string $redirectUri
* *
@ -162,13 +198,12 @@ abstract class AbstractGrant implements GrantTypeInterface
*/ */
public function validateScopes( public function validateScopes(
ServerRequestInterface $request, ServerRequestInterface $request,
$scopeDelimiterString,
ClientEntityInterface $client, ClientEntityInterface $client,
$redirectUri = null $redirectUri = null
) { ) {
$requestedScopes = $this->getRequestParameter('scope', $request); $requestedScopes = $this->getRequestParameter('scope', $request);
$scopesList = array_filter( $scopesList = array_filter(
explode($scopeDelimiterString, trim($requestedScopes)), explode(self::SCOPE_DELIMITER_STRING, trim($requestedScopes)),
function ($scope) { function ($scope) {
return !empty($scope); return !empty($scope);
} }

View File

@ -11,8 +11,6 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -34,8 +32,7 @@ class ClientCredentialsGrant extends AbstractGrant
public function respondToRequest( public function respondToRequest(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseTypeInterface $responseType, ResponseTypeInterface $responseType,
\DateInterval $tokenTTL, \DateInterval $tokenTTL
$scopeDelimiter = ' '
) { ) {
// Validate request // Validate request
$client = $this->validateClient($request); $client = $this->validateClient($request);

View File

@ -13,6 +13,9 @@ namespace League\OAuth2\Server\Grant;
use DateInterval; use DateInterval;
use League\Event\EmitterInterface; use League\Event\EmitterInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -41,15 +44,13 @@ interface GrantTypeInterface
* @param \Psr\Http\Message\ServerRequestInterface $request * @param \Psr\Http\Message\ServerRequestInterface $request
* @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
* @param \DateInterval $tokenTTL * @param \DateInterval $tokenTTL
* @param string $scopeDelimiter
* *
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
*/ */
public function respondToRequest( public function respondToRequest(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseTypeInterface $responseType, ResponseTypeInterface $responseType,
DateInterval $tokenTTL, DateInterval $tokenTTL
$scopeDelimiter = ' '
); );
/** /**
@ -72,4 +73,39 @@ interface GrantTypeInterface
* @param \League\Event\EmitterInterface $emitter * @param \League\Event\EmitterInterface $emitter
*/ */
public function setEmitter(EmitterInterface $emitter); public function setEmitter(EmitterInterface $emitter);
/**
* Set the client repository
*
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
*/
public function setClientRepository(ClientRepositoryInterface $clientRepository);
/**
* Set the access token repository
*
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
*/
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository);
/**
* Set the scope repository
*
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
*/
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
/**
* Set the path to the private key
*
* @param string $pathToPrivateKey
*/
public function setPathToPrivateKey($pathToPrivateKey);
/**
* Set the path to the public key
*
* @param string $pathToPublicKey
*/
public function setPathToPublicKey($pathToPublicKey);
} }

View File

@ -12,13 +12,9 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use League\Event\Event; use League\Event\Event;
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -47,20 +43,12 @@ class PasswordGrant extends AbstractGrant
/** /**
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
*/ */
public function __construct( public function __construct(
UserRepositoryInterface $userRepository, UserRepositoryInterface $userRepository,
ClientRepositoryInterface $clientRepository,
ScopeRepositoryInterface $scopeRepository,
AccessTokenRepositoryInterface $accessTokenRepository,
RefreshTokenRepositoryInterface $refreshTokenRepository RefreshTokenRepositoryInterface $refreshTokenRepository
) { ) {
parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository);
$this->userRepository = $userRepository; $this->userRepository = $userRepository;
$this->refreshTokenRepository = $refreshTokenRepository; $this->refreshTokenRepository = $refreshTokenRepository;
} }
@ -71,8 +59,7 @@ class PasswordGrant extends AbstractGrant
public function respondToRequest( public function respondToRequest(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseTypeInterface $responseType, ResponseTypeInterface $responseType,
\DateInterval $tokenTTL, \DateInterval $tokenTTL
$scopeDelimiter = ' '
) { ) {
// Validate request // Validate request
$client = $this->validateClient($request); $client = $this->validateClient($request);

View File

@ -12,10 +12,7 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use League\OAuth2\Server\Utils\KeyCrypt; use League\OAuth2\Server\Utils\KeyCrypt;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -33,33 +30,17 @@ class RefreshTokenGrant extends AbstractGrant
*/ */
protected $identifier = 'refresh_token'; protected $identifier = 'refresh_token';
/**
* @var string
*/
private $pathToPublicKey;
/** /**
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
*/ */
private $refreshTokenRepository; private $refreshTokenRepository;
/** /**
* @param string $pathToPublicKey
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
*/ */
public function __construct( public function __construct(
$pathToPublicKey,
ClientRepositoryInterface $clientRepository,
ScopeRepositoryInterface $scopeRepository,
AccessTokenRepositoryInterface $accessTokenRepository,
RefreshTokenRepositoryInterface $refreshTokenRepository RefreshTokenRepositoryInterface $refreshTokenRepository
) { ) {
parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository);
$this->pathToPublicKey = $pathToPublicKey;
$this->refreshTokenRepository = $refreshTokenRepository; $this->refreshTokenRepository = $refreshTokenRepository;
} }
@ -69,8 +50,7 @@ class RefreshTokenGrant extends AbstractGrant
public function respondToRequest( public function respondToRequest(
ServerRequestInterface $request, ServerRequestInterface $request,
ResponseTypeInterface $responseType, ResponseTypeInterface $responseType,
\DateInterval $tokenTTL, \DateInterval $tokenTTL
$scopeDelimiter = ' '
) { ) {
$client = $this->validateClient($request); $client = $this->validateClient($request);
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
@ -137,7 +117,7 @@ class RefreshTokenGrant extends AbstractGrant
throw OAuthServerException::invalidRefreshToken( throw OAuthServerException::invalidRefreshToken(
'Token is not linked to client,' . 'Token is not linked to client,' .
' got: ' . $clientId . ' got: ' . $clientId .
' expected: '. $refreshTokenData['client_id'] ' expected: ' . $refreshTokenData['client_id']
); );
} }

View File

@ -0,0 +1,54 @@
<?php
namespace League\OAuth2\Server\Middleware;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Server;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ResourceServerMiddleware
{
/**
* @var \League\OAuth2\Server\Server
*/
private $server;
/**
* ResourceServerMiddleware constructor.
*
* @param \League\OAuth2\Server\Server $server
*/
public function __construct(Server $server)
{
$this->server = $server;
}
/**
* @param \Psr\Http\Message\ServerRequestInterface $request
* @param \Psr\Http\Message\ResponseInterface $response
* @param callable $next
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
if ($request->hasHeader('authorization') === false) {
$exception = OAuthServerException::accessDenied('Missing authorization header');
return $exception->generateHttpResponse($response);
}
$request = $this->server->getResponseType()->determineAccessTokenInHeader($request);
if ($request->getAttribute('oauth_access_token') === null) {
$exception = OAuthServerException::accessDenied('Access token was invalid');
return $exception->generateHttpResponse($response);
}
// Pass the request and response on to the next responder in the chain
return $next($request, $response);
}
}

View File

@ -13,6 +13,7 @@ namespace League\OAuth2\Server\ResponseTypes;
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
abstract class AbstractResponseType implements ResponseTypeInterface abstract class AbstractResponseType implements ResponseTypeInterface
{ {
@ -21,6 +22,11 @@ abstract class AbstractResponseType implements ResponseTypeInterface
*/ */
protected $pathToPrivateKey; protected $pathToPrivateKey;
/**
* @var string
*/
protected $pathToPublicKey;
/** /**
* @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface
*/ */
@ -32,11 +38,23 @@ abstract class AbstractResponseType implements ResponseTypeInterface
protected $refreshToken; protected $refreshToken;
/** /**
* @param string $pathToPrivateKey * @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
*/ */
public function __construct($pathToPrivateKey) protected $accessTokenRepository;
{
/**
* @param string $pathToPrivateKey
* @param string $pathToPublicKey
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
*/
public function __construct(
$pathToPrivateKey,
$pathToPublicKey,
AccessTokenRepositoryInterface $accessTokenRepository
) {
$this->pathToPrivateKey = $pathToPrivateKey; $this->pathToPrivateKey = $pathToPrivateKey;
$this->pathToPublicKey = $pathToPublicKey;
$this->accessTokenRepository = $accessTokenRepository;
} }
/** /**

View File

@ -12,6 +12,7 @@
namespace League\OAuth2\Server\ResponseTypes; namespace League\OAuth2\Server\ResponseTypes;
use Lcobucci\JWT\Builder; use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Rsa\Sha256; use Lcobucci\JWT\Signer\Rsa\Sha256;
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
@ -78,8 +79,28 @@ class BearerTokenResponse extends AbstractResponseType
public function determineAccessTokenInHeader(ServerRequestInterface $request) public function determineAccessTokenInHeader(ServerRequestInterface $request)
{ {
$header = $request->getHeader('authorization'); $header = $request->getHeader('authorization');
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header));
return ($accessToken === 'Bearer') ? '' : $accessToken; try {
// Attempt to parse and validate the JWT
$token = (new Parser())->parse($jwt);
if ($token->verify(new Sha256(), $this->pathToPublicKey) === false) {
return $request;
}
// Check if token has been revoked
if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jwt'))) {
return $request;
}
// Return the request with additional attributes
return $request->withAttribute('oauth_access_token', $token->getClaim('jti'))
->withAttribute('oauth_client_id', $token->getClaim('aud'))
->withAttribute('oauth_user_id', $token->getClaim('sub'))
->withAttribute('oauth_scopes', $token->getClaim('scopes'));
} catch (\InvalidArgumentException $e) {
// JWT couldn't be parsed so return the request as is
return $request;
}
} }
} }

View File

@ -29,11 +29,12 @@ interface ResponseTypeInterface
public function setRefreshToken(RefreshTokenEntityInterface $refreshToken); public function setRefreshToken(RefreshTokenEntityInterface $refreshToken);
/** /**
* Determine the access token in the authorization header * Determine the access token in the authorization header and append OAUth properties to the request
* as attributes
* *
* @param ServerRequestInterface $request * @param ServerRequestInterface $request
* *
* @return string * @return ServerRequestInterface
*/ */
public function determineAccessTokenInHeader(ServerRequestInterface $request); public function determineAccessTokenInHeader(ServerRequestInterface $request);

View File

@ -7,6 +7,9 @@ use League\Event\EmitterAwareInterface;
use League\Event\EmitterAwareTrait; use League\Event\EmitterAwareTrait;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Grant\GrantTypeInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
@ -36,131 +39,101 @@ class Server implements EmitterAwareInterface
/** /**
* @var string * @var string
*/ */
protected $defaultPrivateKeyPath; protected $privateKeyPath;
/** /**
* @var ResponseTypeInterface * @var ResponseTypeInterface
*/ */
protected $defaultResponseType; protected $responseType;
/**
* @var DateInterval
*/
protected $defaultAccessTokenTTL;
/** /**
* @var string * @var string
*/ */
protected $scopeDelimiterString = ' '; private $publicKeyPath;
/**
* @var \League\OAuth2\Server\Repositories\ClientRepositoryInterface
*/
private $clientRepository;
/**
* @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
*/
private $accessTokenRepository;
/**
* @var \League\OAuth2\Server\Repositories\ScopeRepositoryInterface
*/
private $scopeRepository;
/** /**
* New server instance * New server instance
* *
* @param string $defaultPrivateKeyPath * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
* @param DateInterval $defaultAccessTokenTTL * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
* @param string $privateKeyPath
* @param string $publicKeyPath
* @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
*/ */
public function __construct($defaultPrivateKeyPath, \DateInterval $defaultAccessTokenTTL = null) public function __construct(
{ ClientRepositoryInterface $clientRepository,
$this->defaultPrivateKeyPath = $defaultPrivateKeyPath; AccessTokenRepositoryInterface $accessTokenRepository,
$this->defaultAccessTokenTTL = $defaultAccessTokenTTL; ScopeRepositoryInterface $scopeRepository,
$privateKeyPath,
$publicKeyPath,
ResponseTypeInterface $responseType = null
) {
$this->clientRepository = $clientRepository;
$this->accessTokenRepository = $accessTokenRepository;
$this->scopeRepository = $scopeRepository;
$this->privateKeyPath = $privateKeyPath;
$this->publicKeyPath = $publicKeyPath;
$this->responseType = $responseType;
} }
/** /**
* Set the default token type that grants will return * Get the token type that grants will return in the HTTP response
*
* @param ResponseTypeInterface $defaultTokenType
*/
public function setDefaultResponseType(ResponseTypeInterface $defaultTokenType)
{
$this->defaultResponseType = $defaultTokenType;
}
/**
* Get the default token type that grants will return
* *
* @return ResponseTypeInterface * @return ResponseTypeInterface
*/ */
protected function getDefaultResponseType() public function getResponseType()
{ {
if (!$this->defaultResponseType instanceof ResponseTypeInterface) { if (!$this->responseType instanceof ResponseTypeInterface) {
$this->defaultResponseType = new BearerTokenResponse($this->defaultPrivateKeyPath); $this->responseType = new BearerTokenResponse(
$this->privateKeyPath,
$this->publicKeyPath,
$this->accessTokenRepository
);
} }
return $this->defaultResponseType; return $this->responseType;
}
/**
* Set the default TTL of access tokens
*
* @param DateInterval $defaultAccessTokenTTL
*/
public function setDefaultAccessTokenTTL(DateInterval $defaultAccessTokenTTL)
{
$this->defaultAccessTokenTTL = $defaultAccessTokenTTL;
}
/**
* Get the default TTL of access tokens
*
* @return DateInterval
*/
protected function getDefaultAccessTokenTTL()
{
if (!$this->defaultAccessTokenTTL instanceof \DateInterval) {
$this->defaultAccessTokenTTL = new \DateInterval('PT01H'); // default token TTL of 1 hour
}
return $this->defaultAccessTokenTTL;
}
/**
* Set the delimiter string used to separate scopes in a request
*
* @param string $scopeDelimiterString
*/
public function setScopeDelimiterString($scopeDelimiterString)
{
$this->scopeDelimiterString = $scopeDelimiterString;
}
/**
* Get the delimiter string used to separate scopes in a request
*
* @return string
*/
protected function getScopeDelimiterString()
{
return $this->scopeDelimiterString;
} }
/** /**
* Enable a grant type on the server * Enable a grant type on the server
* *
* @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType
* @param ResponseTypeInterface $responseType
* @param DateInterval $accessTokenTTL * @param DateInterval $accessTokenTTL
*/ */
public function enableGrantType( public function enableGrantType(
GrantTypeInterface $grantType, GrantTypeInterface $grantType,
ResponseTypeInterface $responseType = null, \DateInterval $accessTokenTTL
\DateInterval $accessTokenTTL = null
) { ) {
$grantType->setAccessTokenRepository($this->accessTokenRepository);
$grantType->setClientRepository($this->clientRepository);
$grantType->setScopeRepository($this->scopeRepository);
$grantType->setPathToPrivateKey($this->privateKeyPath);
$grantType->setPathToPublicKey($this->publicKeyPath);
$grantType->setEmitter($this->getEmitter()); $grantType->setEmitter($this->getEmitter());
$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
// Set grant response type // Set grant response type
if ($responseType instanceof ResponseTypeInterface) { $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getResponseType();
$this->grantResponseTypes[$grantType->getIdentifier()] = $responseType;
} else {
$this->grantResponseTypes[$grantType->getIdentifier()] = $this->getDefaultResponseType();
}
// Set grant access token TTL // Set grant access token TTL
if ($accessTokenTTL instanceof \DateInterval) {
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
} else {
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $this->getDefaultAccessTokenTTL();
}
} }
/** /**
@ -188,8 +161,7 @@ class Server implements EmitterAwareInterface
$tokenResponse = $grantType->respondToRequest( $tokenResponse = $grantType->respondToRequest(
$request, $request,
$this->grantResponseTypes[$grantType->getIdentifier()], $this->grantResponseTypes[$grantType->getIdentifier()],
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()], $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
$this->getScopeDelimiterString()
); );
} }
} }