mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-01-13 23:32:20 +05:30
Merge branch 'V5-WIP' into secure_body_params_access
This commit is contained in:
commit
95e3c1d1a2
@ -7,7 +7,6 @@
|
||||
"php": ">=5.5.9",
|
||||
"league/event": "~2.1",
|
||||
"zendframework/zend-diactoros": "~1.1",
|
||||
"namshi/jose": "^6.0",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^1.1"
|
||||
},
|
||||
@ -65,5 +64,8 @@
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"league/plates": "Required for parsing authorization code templates"
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@
|
||||
],
|
||||
"require": {
|
||||
"slim/slim": "3.0.*",
|
||||
"league/oauth2-server": "dev-V5-WIP"
|
||||
"league/oauth2-server": "dev-V5-WIP",
|
||||
"league/plates": "^3.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
63
examples/composer.lock
generated
63
examples/composer.lock
generated
@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "ff6f832d21c141662627622e68079ca5",
|
||||
"content-hash": "f08d5c7c3ede910150d75ad3c56d1b46",
|
||||
"hash": "143453cc35e7f499b130b6460222dc5a",
|
||||
"content-hash": "1ea46581fb6db25f323a37a45ef74f95",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
@ -145,9 +145,14 @@
|
||||
{
|
||||
"name": "league/oauth2-server",
|
||||
"version": "dev-V5-WIP",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/oauth2-server.git",
|
||||
"reference": "95919a688e29c911d1e4e83112cacd18f719700f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../",
|
||||
"url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/95919a688e29c911d1e4e83112cacd18f719700f",
|
||||
"reference": "168e7640c6e8217b7e961151de522810b3edce6e",
|
||||
"shasum": null
|
||||
},
|
||||
@ -214,6 +219,58 @@
|
||||
"server"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "league/plates",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/plates.git",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "~1.4.0",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~1.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Plates\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Reinink",
|
||||
"email": "jonathan@reinink.ca",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
|
||||
"homepage": "http://platesphp.com",
|
||||
"keywords": [
|
||||
"league",
|
||||
"package",
|
||||
"templates",
|
||||
"templating",
|
||||
"views"
|
||||
],
|
||||
"time": "2015-07-09 02:14:40"
|
||||
},
|
||||
{
|
||||
"name": "namshi/jose",
|
||||
"version": "6.1.0",
|
||||
|
83
examples/public/auth_code.php
Normal file
83
examples/public/auth_code.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
|
||||
use Slim\App;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
include(__DIR__ . '/../vendor/autoload.php');
|
||||
|
||||
// App
|
||||
$app = new App([
|
||||
Server::class => function () {
|
||||
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$userRepository = new UserRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the password grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
$userRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->any('/authorize', function (Request $request, Response $response) {
|
||||
/** @var Server $server */
|
||||
$server = $this->get(Server::class);
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $e) {
|
||||
return $e->generateHttpResponse($response);
|
||||
} catch (\Exception $e) {
|
||||
return $response->withStatus(500)->write($e->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
$app->post('/access_token', function (Request $request, Response $response) {
|
||||
/** @var Server $server */
|
||||
$server = $this->get(Server::class);
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $e) {
|
||||
return $e->generateHttpResponse($response);
|
||||
} catch (\Exception $e) {
|
||||
return $response->withStatus(500)->write($e->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware;
|
||||
use League\OAuth2\Server\Server;
|
||||
|
||||
@ -10,8 +12,6 @@ use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
|
||||
use Slim\App;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
include(__DIR__ . '/../vendor/autoload.php');
|
||||
|
||||
|
42
examples/src/Repositories/AuthCodeRepository.php
Normal file
42
examples/src/Repositories/AuthCodeRepository.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
|
||||
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Persists a new auth code to permanent storage
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
||||
{
|
||||
// TODO: Implement persistNewAuthCode() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an auth code
|
||||
*
|
||||
* @param string $codeId
|
||||
*/
|
||||
public function revokeAuthCode($codeId)
|
||||
{
|
||||
// TODO: Implement revokeAuthCode() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the auth code has been revoked
|
||||
*
|
||||
* @param string $codeId
|
||||
*
|
||||
* @return bool Return true if this code has been revoked
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId)
|
||||
{
|
||||
// TODO: Implement isAuthCodeRevoked() method.
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ class ClientRepository implements ClientRepositoryInterface
|
||||
'myawesomeapp' => [
|
||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||
'name' => 'My Awesome App',
|
||||
'redirect_uri' => ''
|
||||
'redirect_uri' => 'http://foo/bar'
|
||||
]
|
||||
];
|
||||
|
||||
@ -30,7 +30,7 @@ class ClientRepository implements ClientRepositoryInterface
|
||||
}
|
||||
|
||||
// Check if redirect URI is valid
|
||||
if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirectUri']) {
|
||||
if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirect_uri']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
79
src/Entities/AuthorizationCodeRequestEntity.php
Normal file
79
src/Entities/AuthorizationCodeRequestEntity.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
class AuthorizationCodeRequestEntity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $clientId;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $redirectUri;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $scope;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $state;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getScope()
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* AuthorizationCodeRequestEntity constructor.
|
||||
*
|
||||
* @param string $clientId
|
||||
* @param string|null $redirectUri
|
||||
* @param string|null $scope
|
||||
* @param string|null $state
|
||||
*/
|
||||
public function __construct($clientId, $redirectUri = null, $scope = null, $state = null)
|
||||
{
|
||||
$this->clientId = $clientId;
|
||||
$this->redirectUri = $redirectUri;
|
||||
$this->scope = $scope;
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['clientId', 'redirectUri', 'scope', 'state'];
|
||||
}
|
||||
}
|
@ -197,13 +197,20 @@ class OAuthServerException extends \Exception
|
||||
/**
|
||||
* Access denied
|
||||
*
|
||||
* @param null|string $hint
|
||||
* @param string|null $hint
|
||||
* @param string|null $redirectUri
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function accessDenied($hint = null)
|
||||
public static function accessDenied($hint = null, $redirectUri = null)
|
||||
{
|
||||
return new static('The server denied the request.', 'access_denied', 401, $hint);
|
||||
return new static(
|
||||
'The resource owner or authorization server denied the request.',
|
||||
'access_denied',
|
||||
401,
|
||||
$hint,
|
||||
$redirectUri
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@ use League\Event\EmitterAwareTrait;
|
||||
use League\Event\EmitterInterface;
|
||||
use League\Event\Event;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entities\ScopeEntity;
|
||||
@ -34,13 +35,6 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
|
||||
const SCOPE_DELIMITER_STRING = ' ';
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = '';
|
||||
|
||||
/**
|
||||
* Grant responds with
|
||||
*
|
||||
@ -139,14 +133,6 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -156,14 +142,20 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param bool $validateSecret
|
||||
* @param bool $validateRedirectUri
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
protected function validateClient(
|
||||
ServerRequestInterface $request,
|
||||
$validateSecret = true,
|
||||
$validateRedirectUri = false
|
||||
) {
|
||||
$clientId = $this->getRequestParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
@ -178,15 +170,20 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_PW', $request)
|
||||
);
|
||||
if (is_null($clientSecret)) {
|
||||
if (is_null($clientSecret) && $validateSecret === true) {
|
||||
throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if (is_null($redirectUri) && $validateRedirectUri === true) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$this->getIdentifier(),
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
null
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (!$client instanceof ClientEntityInterface) {
|
||||
@ -199,6 +196,8 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scopes in the request
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $redirectUri
|
||||
@ -249,9 +248,36 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return (is_array($request->getParsedBody()) && isset($request->getParsedBody()[$parameter]))
|
||||
? $request->getParsedBody()[$parameter]
|
||||
: $default;
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve query string parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cookie parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,10 +291,12 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
protected function getServerParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return (isset($request->getServerParams()[$parameter])) ? $request->getServerParams()[$parameter] : $default;
|
||||
return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
*
|
||||
* @param \DateInterval $tokenTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
@ -295,6 +323,39 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an auth code
|
||||
*
|
||||
* @param \DateInterval $tokenTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
* @param string $redirectUri
|
||||
* @param array $scopes
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\AuthCodeEntity
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
protected function issueAuthCode(
|
||||
\DateInterval $tokenTTL,
|
||||
ClientEntityInterface $client,
|
||||
$userIdentifier,
|
||||
$redirectUri,
|
||||
array $scopes = []
|
||||
) {
|
||||
$authCode = new AuthCodeEntity();
|
||||
$authCode->setIdentifier(SecureKey::generate());
|
||||
$authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
$authCode->setRedirectUri($redirectUri);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$authCode->addScope($scope);
|
||||
}
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken
|
||||
*
|
||||
@ -315,10 +376,11 @@ abstract class AbstractGrant implements GrantTypeInterface
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
|
||||
return (
|
||||
is_array($request->getParsedBody())
|
||||
&& isset($request->getParsedBody()['grant_type'])
|
||||
&& $request->getParsedBody()['grant_type'] === $this->identifier
|
||||
array_key_exists('grant_type', $requestParameters)
|
||||
&& $requestParameters['grant_type'] === $this->getIdentifier()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,303 +1,357 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code grant
|
||||
*
|
||||
* @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\Grant;
|
||||
|
||||
use League\Event\Emitter;
|
||||
use League\Event\Event;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Exception\InvalidClientException;
|
||||
use League\OAuth2\Server\Exception\InvalidRequestException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\TokenTypes\TokenTypeInterface;
|
||||
use League\OAuth2\Server\Utils\SecureKey;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use League\OAuth2\Server\Utils\KeyCrypt;
|
||||
use League\Plates\Engine;
|
||||
use League\Event\Event;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Uri;
|
||||
|
||||
/**
|
||||
* Auth code grant class
|
||||
*/
|
||||
class AuthCodeGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
private $authCodeTTL;
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface
|
||||
*/
|
||||
protected $authCodeRepository;
|
||||
private $authCodeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
|
||||
*/
|
||||
private $userRepository;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $pathToLoginTemplate;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $pathToAuthorizeTemplate;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
|
||||
*/
|
||||
private $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* @param \League\Event\Emitter $emitter
|
||||
* @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\AuthCodeRepositoryInterface $authCodeRepository
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
|
||||
* @param \DateInterval $authCodeTTL
|
||||
* @param string|null $pathToLoginTemplate
|
||||
* @param string|null $pathToAuthorizeTemplate
|
||||
*/
|
||||
public function __construct(
|
||||
Emitter $emitter,
|
||||
ClientRepositoryInterface $clientRepository,
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||
AuthCodeRepositoryInterface $authCodeRepository,
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository = null
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository,
|
||||
UserRepositoryInterface $userRepository,
|
||||
\DateInterval $authCodeTTL,
|
||||
$pathToLoginTemplate = null,
|
||||
$pathToAuthorizeTemplate = null
|
||||
) {
|
||||
$this->authCodeRepository = $authCodeRepository;
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
parent::__construct($emitter, $clientRepository, $scopeRepository, $accessTokenRepository);
|
||||
$this->userRepository = $userRepository;
|
||||
$this->authCodeTTL = $authCodeTTL;
|
||||
$this->pathToLoginTemplate = ($pathToLoginTemplate === null)
|
||||
? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php'
|
||||
: $this->pathToLoginTemplate;
|
||||
$this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null)
|
||||
? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php'
|
||||
: $this->pathToAuthorizeTemplate;
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'authorization_code';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* Respond to an authorization request
|
||||
*
|
||||
* @var string
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
protected $responseType = 'code';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* The TTL of the auth token
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $authTokenTTL = 600;
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
*
|
||||
* @param int $authTokenTTL
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAuthTokenTTL($authTokenTTL)
|
||||
{
|
||||
$this->authTokenTTL = $authTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check authorize parameters
|
||||
*
|
||||
* @return array Authorize request parameters
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
/*public function checkAuthorizeParams()
|
||||
{
|
||||
// Get required params
|
||||
$clientId = $request->query->get('client_id', null);
|
||||
protected function respondToAuthorizationRequest(
|
||||
ServerRequestInterface $request
|
||||
) {
|
||||
$clientId = $this->getQueryStringParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw new InvalidRequestException('client_id');
|
||||
throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$redirectUri = $request->query->get('redirect_uri', null);
|
||||
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null);
|
||||
if (is_null($redirectUri)) {
|
||||
throw new InvalidRequestException('redirect_uri');
|
||||
throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
null,
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($request));
|
||||
throw new Exception\InvalidClientException();
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->emitter->emit(new Event('client.authentication.failed', $request));
|
||||
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$state = $request->query->get('state', null);
|
||||
if ($this->server->stateParamRequired() === true && is_null($state)) {
|
||||
throw new InvalidRequestException('state', $redirectUri);
|
||||
}
|
||||
|
||||
$responseType = $request->query->get('response_type', null);
|
||||
if (is_null($responseType)) {
|
||||
throw new InvalidRequestException('response_type', $redirectUri);
|
||||
}
|
||||
|
||||
// Ensure response type is one that is recognised
|
||||
if (!in_array($responseType, $this->server->getResponseTypes())) {
|
||||
throw new Exception\UnsupportedResponseTypeException($responseType, $redirectUri);
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scopeParam = $request->query->get('scope', '');
|
||||
$scopes = $this->validateScopes($scopeParam, $client, $redirectUri);
|
||||
|
||||
return [
|
||||
'client' => $client,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'state' => $state,
|
||||
'response_type' => $responseType,
|
||||
'scopes' => $scopes
|
||||
];
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Parse a new authorize request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authParams The authorize request $_GET parameters
|
||||
*
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
/*public function newAuthorizeRequest($type, $typeId, $authParams = [])
|
||||
{
|
||||
// Create a new session
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setOwner($type, $typeId);
|
||||
$session->associateClient($authParams['client']);
|
||||
$session->save();
|
||||
|
||||
// Create a new auth code
|
||||
$authCode = new AuthCodeEntity($this->server);
|
||||
$authCode->setId(SecureKey::generate());
|
||||
$authCode->setRedirectUri($authParams['redirect_uri']);
|
||||
$authCode->setExpireTime(time() + $this->authTokenTTL);
|
||||
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$authCode->associateScope($scope);
|
||||
}
|
||||
|
||||
$authCode->setSession($session);
|
||||
$authCode->save();
|
||||
|
||||
return $authCode->generateRedirectUri($authParams['state']);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Return an access token
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
* @param string $scopeDelimiter
|
||||
*
|
||||
* @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface
|
||||
* @throws \League\OAuth2\Server\Exception\InvalidClientException
|
||||
* @throws \League\OAuth2\Server\Exception\InvalidGrantException
|
||||
* @throws \League\OAuth2\Server\Exception\InvalidRequestException
|
||||
*/
|
||||
public function getAccessTokenAsType(
|
||||
Request $request,
|
||||
TokenTypeInterface $tokenType,
|
||||
DateInterval $accessTokenTTL,
|
||||
$scopeDelimiter = ' '
|
||||
) {
|
||||
// Get the required params
|
||||
$clientId = $request->request->get('client_id', $request->getUser());
|
||||
if (is_null($clientId)) {
|
||||
throw new InvalidRequestException('client_id', '');
|
||||
}
|
||||
|
||||
$clientSecret = $request->request->get('client_secret',
|
||||
$request->getPassword());
|
||||
if (is_null($clientSecret)) {
|
||||
throw new InvalidRequestException('client_secret');
|
||||
}
|
||||
|
||||
$redirectUri = $request->request->get('redirect_uri', null);
|
||||
if (is_null($redirectUri)) {
|
||||
throw new InvalidRequestException('redirect_uri');
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$client = $this->clientRepository->get(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
$scopes = $this->validateScopes($request, $client, $redirectUri);
|
||||
$queryString = http_build_query($request->getQueryParams());
|
||||
$postbackUri = new Uri(
|
||||
sprintf(
|
||||
'//%s%s',
|
||||
$request->getServerParams()['HTTP_HOST'],
|
||||
$request->getServerParams()['REQUEST_URI']
|
||||
)
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntityInterface) === false) {
|
||||
$this->emitter->emit(new Event('client.authentication.failed', $request));
|
||||
throw new InvalidClientException();
|
||||
$userId = null;
|
||||
$userHasApprovedClient = null;
|
||||
if ($this->getRequestParameter('action', $request, null) !== null) {
|
||||
$userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve');
|
||||
}
|
||||
|
||||
// Validate the auth code
|
||||
$authCode = $request->request->get('code', null);
|
||||
if (is_null($authCode)) {
|
||||
throw new InvalidRequestException('code');
|
||||
// Check if the user has been authenticated
|
||||
$oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null);
|
||||
if ($oauthCookie !== null) {
|
||||
try {
|
||||
$oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey));
|
||||
if (is_object($oauthCookiePayload)) {
|
||||
$userId = $oauthCookiePayload->user_id;
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::serverError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$code = $this->authCodeRepository->get($authCode);
|
||||
if (($code instanceof AuthCodeEntityInterface) === false) {
|
||||
throw new InvalidRequestException('code');
|
||||
// The username + password might be available in $_POST
|
||||
$usernameParameter = $this->getRequestParameter('username', $request, null);
|
||||
$passwordParameter = $this->getRequestParameter('password', $request, null);
|
||||
|
||||
$loginError = null;
|
||||
|
||||
// Assert if the user has logged in already
|
||||
if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) {
|
||||
$userEntity = $this->userRepository->getUserEntityByUserCredentials(
|
||||
$usernameParameter,
|
||||
$passwordParameter
|
||||
);
|
||||
|
||||
if ($userEntity instanceof UserEntityInterface) {
|
||||
$userId = $userEntity->getIdentifier();
|
||||
} else {
|
||||
$loginError = 'Incorrect username or password';
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the auth code hasn't expired
|
||||
if ($code->isExpired() === true) {
|
||||
throw new InvalidRequestException('code');
|
||||
// The user hasn't logged in yet so show a login form
|
||||
if ($userId === null) {
|
||||
$engine = new Engine(dirname($this->pathToLoginTemplate));
|
||||
$html = $engine->render(
|
||||
'login_user',
|
||||
[
|
||||
'error' => $loginError,
|
||||
'postback_uri' => (string) $postbackUri->withQuery($queryString),
|
||||
]
|
||||
);
|
||||
|
||||
return new Response\HtmlResponse($html);
|
||||
}
|
||||
|
||||
// Check redirect URI presented matches redirect URI originally used in authorize request
|
||||
if ($code->getRedirectUri() !== $redirectUri) {
|
||||
throw new InvalidRequestException('redirect_uri');
|
||||
|
||||
// The user hasn't approved the client yet so show an authorize form
|
||||
if ($userId !== null && $userHasApprovedClient === null) {
|
||||
$engine = new Engine(dirname($this->pathToAuthorizeTemplate));
|
||||
$html = $engine->render(
|
||||
'authorize_client',
|
||||
[
|
||||
'client' => $client,
|
||||
'scopes' => $scopes,
|
||||
'postback_uri' => (string) $postbackUri->withQuery($queryString),
|
||||
]
|
||||
);
|
||||
|
||||
return new Response\HtmlResponse(
|
||||
$html,
|
||||
200,
|
||||
[
|
||||
'Set-Cookie' => sprintf(
|
||||
'oauth_authorize_request=%s; Expires=%s',
|
||||
urlencode(KeyCrypt::encrypt(
|
||||
json_encode([
|
||||
'user_id' => $userId,
|
||||
]),
|
||||
$this->pathToPrivateKey
|
||||
)),
|
||||
(new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e')
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Generate the access token
|
||||
$accessToken = new AccessTokenEntity($this->server);
|
||||
$accessToken->setIdentifier(SecureKey::generate());
|
||||
$expirationDateTime = (new \DateTime())->add($accessTokenTTL);
|
||||
$accessToken->setExpiryDateTime($expirationDateTime);
|
||||
$accessToken->setClient($client);
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
|
||||
foreach ($code->getScopes() as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
$redirectUri = new Uri($redirectUri);
|
||||
parse_str($redirectUri->getQuery(), $redirectPayload);
|
||||
if ($stateParameter !== null) {
|
||||
$redirectPayload['state'] = $stateParameter;
|
||||
}
|
||||
|
||||
$tokenType->setAccessToken($accessToken);
|
||||
if ($userHasApprovedClient === true) {
|
||||
$authCode = $this->issueAuthCode(
|
||||
$this->authCodeTTL,
|
||||
$client,
|
||||
$userId,
|
||||
$redirectUri,
|
||||
$scopes
|
||||
);
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->refreshTokenRepository instanceof RefreshTokenRepositoryInterface) {
|
||||
// $refreshToken = new RefreshTokenEntity($this->server);
|
||||
// $refreshToken->setId(SecureKey::generate());
|
||||
// $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time());
|
||||
// $tokenType->setParam('refresh_token', $refreshToken->getId());
|
||||
// $refreshToken->setAccessToken($accessToken);
|
||||
$redirectPayload['code'] = KeyCrypt::encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||
'auth_code_id' => $authCode->getIdentifier(),
|
||||
'scopes' => $authCode->getScopes(),
|
||||
'user_id' => $authCode->getUserIdentifier(),
|
||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||
]
|
||||
),
|
||||
$this->pathToPrivateKey
|
||||
);
|
||||
|
||||
return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload)));
|
||||
}
|
||||
|
||||
// Expire the auth code
|
||||
$this->authCodeRepository->delete($code);
|
||||
$exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri);
|
||||
return $exception->generateHttpResponse();
|
||||
}
|
||||
|
||||
// Save the access token
|
||||
$this->accessTokenRepository->create($accessToken);
|
||||
/**
|
||||
* Respond to an access token request
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
protected function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$encryptedAuthCode = $this->getRequestParameter('code', $request, null);
|
||||
|
||||
return $tokenType;
|
||||
if ($encryptedAuthCode === null) {
|
||||
throw OAuthServerException::invalidRequest('code');
|
||||
}
|
||||
|
||||
// Validate the authorization code
|
||||
try {
|
||||
$authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthCode, $this->pathToPublicKey));
|
||||
if (time() > $authCodePayload->expire_time) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
|
||||
}
|
||||
|
||||
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
|
||||
}
|
||||
|
||||
if ($authCodePayload->client_id !== $client->getIdentifier()) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::invalidRequest('code', null, 'Cannot decrypt the authorization code');
|
||||
}
|
||||
|
||||
// Issue and persist access + refresh tokens
|
||||
$accessToken = $this->issueAccessToken(
|
||||
$accessTokenTTL,
|
||||
$client,
|
||||
$authCodePayload->user_id,
|
||||
$authCodePayload->scopes
|
||||
);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
|
||||
// Inject tokens into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return (
|
||||
(
|
||||
isset($request->getQueryParams()['response_type'])
|
||||
&& $request->getQueryParams()['response_type'] === 'code'
|
||||
&& isset($request->getQueryParams()['client_id'])
|
||||
) || (parent::canRespondToRequest($request))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'authorization_code';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
if (
|
||||
isset($request->getQueryParams()['response_type'])
|
||||
&& $request->getQueryParams()['response_type'] === 'code'
|
||||
&& isset($request->getQueryParams()['client_id'])
|
||||
) {
|
||||
return $this->respondToAuthorizationRequest($request);
|
||||
} elseif (
|
||||
isset($request->getParsedBody()['grant_type'])
|
||||
&& $request->getParsedBody()['grant_type'] === 'authorization_code'
|
||||
) {
|
||||
return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL);
|
||||
} else {
|
||||
throw OAuthServerException::serverError('respondToRequest() should not have been called');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,6 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
*/
|
||||
class ClientCredentialsGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'client_credentials';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -47,4 +40,12 @@ class ClientCredentialsGrant extends AbstractGrant
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'client_credentials';
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ interface GrantTypeInterface extends EmitterAwareInterface
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL);
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* Return the grant identifier that can be used in matching up requests
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -24,13 +24,6 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
*/
|
||||
class PasswordGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'password';
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
|
||||
*/
|
||||
@ -109,4 +102,12 @@ class PasswordGrant extends AbstractGrant
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,6 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
*/
|
||||
class RefreshTokenGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'refresh_token';
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
|
||||
*/
|
||||
@ -133,4 +126,12 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
|
||||
return $refreshTokenData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'refresh_token';
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
class AuthenticationServerMiddleware
|
||||
{
|
||||
@ -38,9 +39,10 @@ class AuthenticationServerMiddleware
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
|
||||
if (in_array($response->getStatusCode(), [400, 401, 500])) {
|
||||
|
@ -6,6 +6,7 @@ use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
class ResourceServerMiddleware
|
||||
{
|
||||
@ -34,13 +35,14 @@ class ResourceServerMiddleware
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
|
||||
{
|
||||
try {
|
||||
$request = $this->server->getResponseType()->determineAccessTokenInHeader($request);
|
||||
$request = $this->server->validateRequest($request);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
|
||||
// Pass the request and response on to the next responder in the chain
|
||||
|
@ -19,27 +19,25 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
interface AuthCodeRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get the auth code
|
||||
* Persists a new auth code to permanent storage
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity
|
||||
*/
|
||||
public function getAuthCodeEntityByCodeString($code);
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
|
||||
|
||||
/**
|
||||
* Persist a new authorization code
|
||||
* Revoke an auth code
|
||||
*
|
||||
* @param string $code The authorization code string
|
||||
* @param integer $expireTime Token expire time
|
||||
* @param string $redirectUri Client redirect uri
|
||||
* @param string $codeId
|
||||
*/
|
||||
public function persistNewAuthCode($code, $expireTime, $redirectUri);
|
||||
public function revokeAuthCode($codeId);
|
||||
|
||||
/**
|
||||
* Delete an access token
|
||||
* Check if the auth code has been revoked
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $token The access token to delete
|
||||
* @param string $codeId
|
||||
*
|
||||
* @return bool Return true if this code has been revoked
|
||||
*/
|
||||
public function deleteAuthCodeEntity(AuthCodeEntityInterface $token);
|
||||
public function isAuthCodeRevoked($codeId);
|
||||
}
|
||||
|
@ -65,12 +65,13 @@ class BearerTokenResponse extends AbstractResponseType
|
||||
$responseParams['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
$response
|
||||
$response = $response
|
||||
->withStatus(200)
|
||||
->withHeader('pragma', 'no-cache')
|
||||
->withHeader('cache-control', 'no-store')
|
||||
->withHeader('content-type', 'application/json;charset=UTF-8')
|
||||
->getBody()->write(json_encode($responseParams));
|
||||
->withHeader('content-type', 'application/json; charset=UTF-8');
|
||||
|
||||
$response->getBody()->write(json_encode($responseParams));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
35
src/ResponseTypes/DefaultTemplates/authorize_client.php
Normal file
35
src/ResponseTypes/DefaultTemplates/authorize_client.php
Normal file
@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Authorize <?=$this->e($client->getName())?></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Authorize <?=$this->e($client->getName())?>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
Do you want to authorize <?=$this->e($client->getName())?> to access the following data?
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<?php foreach ($scopes as $scope): ?>
|
||||
<li><?=$scope->getIdentifier()?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<form method="POST">
|
||||
<input type="hidden" value="approve" name="action">
|
||||
<button type="submit">Approve</button>
|
||||
</form>
|
||||
|
||||
<form method="POST">
|
||||
<input type="hidden" value="deny" name="action">
|
||||
<button type="submit">Deny</button>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
35
src/ResponseTypes/DefaultTemplates/login_user.php
Normal file
35
src/ResponseTypes/DefaultTemplates/login_user.php
Normal file
@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Login</h1>
|
||||
|
||||
<?php if ($error !== null): ?>
|
||||
<div style="border:solid 1px red; padding: 1rem; margin-bottom:1rem">
|
||||
<?=$this->e($error)?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username">
|
||||
|
||||
<br>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password">
|
||||
|
||||
<br>
|
||||
|
||||
<input type="submit" value="Login">
|
||||
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use DateInterval;
|
||||
use League\Event\EmitterAwareInterface;
|
||||
use League\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
@ -26,7 +27,7 @@ class Server implements EmitterAwareInterface
|
||||
protected $enabledGrantTypes = [];
|
||||
|
||||
/**
|
||||
* @var DateInterval[]
|
||||
* @var \DateInterval[]
|
||||
*/
|
||||
protected $grantTypeAccessTokenTTL = [];
|
||||
|
||||
@ -90,9 +91,9 @@ class Server implements EmitterAwareInterface
|
||||
* Enable a grant type on the server
|
||||
*
|
||||
* @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType
|
||||
* @param DateInterval $accessTokenTTL
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*/
|
||||
public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL)
|
||||
public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL)
|
||||
{
|
||||
$grantType->setAccessTokenRepository($this->accessTokenRepository);
|
||||
$grantType->setClientRepository($this->clientRepository);
|
||||
@ -136,19 +137,37 @@ class Server implements EmitterAwareInterface
|
||||
}
|
||||
}
|
||||
|
||||
if (!$tokenResponse instanceof ResponseTypeInterface) {
|
||||
if ($tokenResponse instanceof ResponseInterface) {
|
||||
return $tokenResponse;
|
||||
}
|
||||
|
||||
if ($tokenResponse instanceof ResponseTypeInterface === false) {
|
||||
return OAuthServerException::unsupportedGrantType()->generateHttpResponse($response);
|
||||
}
|
||||
|
||||
return $tokenResponse->generateHttpResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token validity
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @return \Psr\Http\Message\ServerRequestInterface
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*/
|
||||
public function validateRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->getResponseType()->determineAccessTokenInHeader($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token type that grants will return in the HTTP response
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
public function getResponseType()
|
||||
protected function getResponseType()
|
||||
{
|
||||
if (!$this->responseType instanceof ResponseTypeInterface) {
|
||||
$this->responseType = new BearerTokenResponse(
|
||||
|
@ -51,6 +51,8 @@ class KeyCrypt
|
||||
* @param string $encryptedData
|
||||
* @param string $pathToPublicKey
|
||||
*
|
||||
* @throws \LogicException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function decrypt($encryptedData, $pathToPublicKey)
|
||||
|
Loading…
x
Reference in New Issue
Block a user