Merge branch 'V5-WIP' of github.com:thephpleague/oauth2-server into V5-WIP

This commit is contained in:
Alex Bilbie
2016-03-15 21:21:08 +00:00
20 changed files with 130 additions and 147 deletions

View File

@@ -1,15 +0,0 @@
<?php
namespace League\OAuth2\Server\Entities;
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\ClientEntityTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
/**
* Class ClientEntity.
*/
class ClientEntity implements ClientEntityInterface
{
use EntityTrait, ClientEntityTrait;
}

View File

@@ -1,22 +0,0 @@
<?php
namespace League\OAuth2\Server\Entities;
use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
/**
* Class ScopeEntity.
*/
class ScopeEntity implements ScopeEntityInterface
{
use EntityTrait;
/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return $this->getIdentifier();
}
}

View File

@@ -1,77 +0,0 @@
<?php
namespace League\OAuth2\Server\Entities\Traits;
trait ClientEntityTrait
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $secret;
/**
* @var string
*/
protected $redirectUri;
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function canKeepASecret()
{
return $this->secret !== null;
}
/**
* {@inheritdoc}
*/
public function setSecret($secret)
{
$this->secret = $secret;
}
/**
* {@inheritdoc}
*/
public function validateSecret($submittedSecret)
{
return strcmp((string) $submittedSecret, $this->secret) === 0;
}
/**
* {@inheritdoc}
*/
public function setRedirectUri($redirectUri)
{
$this->redirectUri = $redirectUri;
}
/**
* {@inheritdoc}
*/
public function getRedirectUri()
{
return $this->redirectUri;
}
}

View File

@@ -11,20 +11,19 @@
namespace League\OAuth2\Server\Grant;
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\Interfaces\ScopeEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntity;
use League\OAuth2\Server\Entities\ScopeEntity;
use League\OAuth2\Server\Exception\OAuthServerException;
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 OAuth2ServerExamples\Repositories\AuthCodeRepository;
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
@@ -59,12 +58,17 @@ abstract class AbstractGrant implements GrantTypeInterface
/**
* @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface
*/
private $authCodeRepository;
protected $authCodeRepository;
/**
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
*/
private $refreshTokenRepository;
protected $refreshTokenRepository;
/**
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
*/
protected $userRepository;
/**
* @var string
@@ -121,6 +125,14 @@ abstract class AbstractGrant implements GrantTypeInterface
$this->authCodeRepository = $authCodeRepository;
}
/**
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
*/
public function setUserRepository(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* @param string $pathToPrivateKey
*/
@@ -137,14 +149,6 @@ abstract class AbstractGrant implements GrantTypeInterface
$this->pathToPublicKey = $pathToPublicKey;
}
/**
* {@inheritdoc}
*/
public function setEmitter(EmitterInterface $emitter = null)
{
$this->emitter = $emitter;
}
/**
* {@inheritdoc}
*/
@@ -153,22 +157,6 @@ abstract class AbstractGrant implements GrantTypeInterface
$this->refreshTokenTTL = $refreshTokenTTL;
}
/**
* @return AuthCodeRepositoryInterface
*/
protected function getAuthCodeRepository()
{
return $this->authCodeRepository;
}
/**
* @return RefreshTokenRepositoryInterface
*/
protected function getRefreshTokenRepository()
{
return $this->refreshTokenRepository;
}
/**
* Validate the client.
*
@@ -226,22 +214,21 @@ abstract class AbstractGrant implements GrantTypeInterface
/**
* Validate scopes in the request.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @param string $scopes
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $redirectUri
*
* @throws \League\OAuth2\Server\Exception\OAuthServerException
*
* @return \League\OAuth2\Server\Entities\ScopeEntity[]
* @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[]
*/
public function validateScopes(
ServerRequestInterface $request,
$scopes,
ClientEntityInterface $client,
$redirectUri = null
) {
$requestedScopes = $this->getRequestParameter('scope', $request);
$scopesList = array_filter(
explode(self::SCOPE_DELIMITER_STRING, trim($requestedScopes)),
explode(self::SCOPE_DELIMITER_STRING, trim($scopes)),
function ($scope) {
return !empty($scope);
}
@@ -255,7 +242,7 @@ abstract class AbstractGrant implements GrantTypeInterface
$client->getIdentifier()
);
if (($scope instanceof ScopeEntity) === false) {
if (($scope instanceof ScopeEntityInterface) === false) {
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
}
@@ -326,10 +313,10 @@ abstract class AbstractGrant implements GrantTypeInterface
/**
* Issue an access token.
*
* @param \DateInterval $tokenTTL
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $userIdentifier
* @param array $scopes
* @param \DateInterval $tokenTTL
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $userIdentifier
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes
*
* @return \League\OAuth2\Server\Entities\AccessTokenEntity
*/
@@ -346,11 +333,6 @@ abstract class AbstractGrant implements GrantTypeInterface
$accessToken->setUserIdentifier($userIdentifier);
foreach ($scopes as $scope) {
if (is_string($scope)) {
$s = new ScopeEntity();
$s->setIdentifier($scope);
$scope = $s;
}
$accessToken->addScope($scope);
}
@@ -362,11 +344,11 @@ abstract class AbstractGrant implements GrantTypeInterface
/**
* Issue an auth code.
*
* @param \DateInterval $tokenTTL
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $userIdentifier
* @param string $redirectUri
* @param array $scopes
* @param \DateInterval $tokenTTL
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
* @param string $userIdentifier
* @param string $redirectUri
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes
*
* @throws \League\OAuth2\Server\Exception\OAuthServerException
*

View File

@@ -24,11 +24,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
*/
private $authCodeTTL;
/**
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
*/
private $userRepository;
/**
* @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
@@ -49,7 +44,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
) {
$this->setAuthCodeRepository($authCodeRepository);
$this->setRefreshTokenRepository($refreshTokenRepository);
$this->userRepository = $userRepository;
$this->setUserRepository($userRepository);
$this->authCodeTTL = $authCodeTTL;
$this->refreshTokenTTL = new \DateInterval('P1M');
$this->loginTemplate = $loginTemplate;
@@ -94,7 +89,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
throw OAuthServerException::invalidClient();
}
$scopes = $this->validateScopes($request, $client, $client->getRedirectUri());
$scopes = $this->validateScopes(
$this->getQueryStringParameter('scope', $request),
$client,
$client->getRedirectUri()
);
$queryString = http_build_query($request->getQueryParams());
$postbackUri = new Uri(
sprintf(
@@ -258,7 +257,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
}
if ($this->getAuthCodeRepository()->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
}
@@ -269,17 +268,27 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
if ($authCodePayload->redirect_uri !== $redirectUri) {
throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
}
$scopes = [];
foreach ($authCodePayload->scopes as $scopeId) {
$scope = $this->scopeRepository->getScopeEntityByIdentifier(
$scopeId,
$this->getIdentifier(),
$client->getIdentifier()
);
if (!$scope) {
throw OAuthServerException::invalidScope($scopeId);
}
$scopes[] = $scope;
}
} catch (\LogicException $e) {
throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code');
}
// Issue and persist access + refresh tokens
$accessToken = $this->issueAccessToken(
$accessTokenTTL,
$client,
$authCodePayload->user_id,
$authCodePayload->scopes
);
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
$refreshToken = $this->issueRefreshToken($accessToken);
// Inject tokens into response type

View File

@@ -28,7 +28,7 @@ class ClientCredentialsGrant extends AbstractGrant
) {
// Validate request
$client = $this->validateClient($request);
$scopes = $this->validateScopes($request, $client);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
// Issue and persist access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes);

View File

@@ -16,11 +16,6 @@ use Zend\Diactoros\Uri;
class ImplicitGrant extends AbstractAuthorizeGrant
{
/**
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
*/
private $userRepository;
/**
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
* @param string|null $loginTemplate
@@ -33,7 +28,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
$authorizeTemplate = null,
RendererInterface $templateRenderer = null
) {
$this->userRepository = $userRepository;
$this->setUserRepository($userRepository);
$this->refreshTokenTTL = new \DateInterval('P1M');
$this->loginTemplate = $loginTemplate;
$this->authorizeTemplate = $authorizeTemplate;
@@ -94,7 +89,11 @@ class ImplicitGrant extends AbstractAuthorizeGrant
throw OAuthServerException::invalidClient();
}
$scopes = $this->validateScopes($request, $client, $client->getRedirectUri());
$scopes = $this->validateScopes(
$this->getQueryStringParameter('scope', $request),
$client,
$client->getRedirectUri()
);
$queryString = http_build_query($request->getQueryParams());
$postbackUri = new Uri(
sprintf(
@@ -197,7 +196,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant
$scopes
);
$redirectPayload['access_token'] = $accessToken->convertToJWT($this->pathToPrivateKey);
$redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->pathToPrivateKey);
$redirectPayload['token_type'] = 'bearer';
$redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp();

View File

@@ -23,11 +23,6 @@ use Psr\Http\Message\ServerRequestInterface;
*/
class PasswordGrant extends AbstractGrant
{
/**
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
*/
private $userRepository;
/**
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
@@ -36,7 +31,7 @@ class PasswordGrant extends AbstractGrant
UserRepositoryInterface $userRepository,
RefreshTokenRepositoryInterface $refreshTokenRepository
) {
$this->userRepository = $userRepository;
$this->setUserRepository($userRepository);
$this->setRefreshTokenRepository($refreshTokenRepository);
$this->refreshTokenTTL = new \DateInterval('P1M');
@@ -53,7 +48,7 @@ class PasswordGrant extends AbstractGrant
// Validate request
$client = $this->validateClient($request);
$user = $this->validateUser($request);
$scopes = $this->validateScopes($request, $client);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
// Issue and persist new tokens
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);

View File

@@ -11,7 +11,6 @@
namespace League\OAuth2\Server\Grant;
use League\Event\Event;
use League\OAuth2\Server\Entities\ScopeEntity;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
@@ -44,13 +43,20 @@ class RefreshTokenGrant extends AbstractGrant
// Validate request
$client = $this->validateClient($request);
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
$scopes = $this->validateScopes($request, $client);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
// If no new scopes are requested then give the access token the original session scopes
if (count($scopes) === 0) {
$scopes = array_map(function ($scopeId) {
$scope = new ScopeEntity();
$scope->setIdentifier($scopeId);
$scopes = array_map(function ($scopeId) use ($client) {
$scope = $this->scopeRepository->getScopeEntityByIdentifier(
$scopeId,
$this->getIdentifier(),
$client->getIdentifier()
);
if (!$scope) {
throw OAuthServerException::invalidScope($scopeId);
}
return $scope;
}, $oldRefreshToken['scopes']);
@@ -68,13 +74,13 @@ class RefreshTokenGrant extends AbstractGrant
// Expire old tokens
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
$this->getRefreshTokenRepository()->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
// Issue and persist new tokens
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
$refreshToken = $this->issueRefreshToken($accessToken);
$this->accessTokenRepository->persistNewAccessToken($accessToken);
$this->getRefreshTokenRepository()->persistNewRefreshToken($refreshToken);
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
// Inject tokens into response
$responseType->setAccessToken($accessToken);
@@ -120,7 +126,7 @@ class RefreshTokenGrant extends AbstractGrant
throw OAuthServerException::invalidRefreshToken('Token has expired');
}
if ($this->getRefreshTokenRepository()->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) {
if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) {
throw OAuthServerException::invalidRefreshToken('Token has been revoked');
}

View File

@@ -128,7 +128,8 @@ class Server implements EmitterAwareInterface
}
$tokenResponse = null;
foreach ($this->enabledGrantTypes as $grantType) {
while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) {
/** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */
if ($grantType->canRespondToRequest($request)) {
$tokenResponse = $grantType->respondToRequest(
$request,
@@ -142,11 +143,11 @@ class Server implements EmitterAwareInterface
return $tokenResponse;
}
if ($tokenResponse instanceof ResponseTypeInterface === false) {
return OAuthServerException::unsupportedGrantType()->generateHttpResponse($response);
if ($tokenResponse instanceof ResponseTypeInterface) {
return $tokenResponse->generateHttpResponse($response);
}
return $tokenResponse->generateHttpResponse($response);
throw OAuthServerException::unsupportedGrantType();
}
/**