Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for the "authorization_code" grant type
- Loading branch information
Showing
29 changed files
with
1,200 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\Controller; | ||
|
||
use League\OAuth2\Server\AuthorizationServer; | ||
use League\OAuth2\Server\Exception\OAuthServerException; | ||
use Psr\Http\Message\ResponseFactoryInterface; | ||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Message\ServerRequestInterface; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Symfony\Component\Security\Core\Security; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent; | ||
use Trikoder\Bundle\OAuth2Bundle\League\Entity\User; | ||
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events; | ||
|
||
final class AuthorizationController | ||
{ | ||
/** | ||
* @var AuthorizationServer | ||
*/ | ||
private $server; | ||
|
||
/** | ||
* @var Security | ||
*/ | ||
private $security; | ||
|
||
/** | ||
* @var EventDispatcherInterface | ||
*/ | ||
private $eventDispatcher; | ||
|
||
public function __construct(AuthorizationServer $server, Security $security, EventDispatcherInterface $eventDispatcher) | ||
{ | ||
$this->server = $server; | ||
$this->security = $security; | ||
$this->eventDispatcher = $eventDispatcher; | ||
} | ||
|
||
public function indexAction(ServerRequestInterface $serverRequest, ResponseFactoryInterface $responseFactory): ResponseInterface | ||
{ | ||
$serverResponse = $responseFactory->createResponse(); | ||
|
||
try { | ||
$authRequest = $this->server->validateAuthorizationRequest($serverRequest); | ||
$authRequest->setUser($this->getUserEntity()); | ||
|
||
/** @var AuthorizationRequestResolveEvent $event */ | ||
$event = $this->eventDispatcher->dispatch( | ||
OAuth2Events::AUTHORIZATION_REQUEST_RESOLVE, | ||
new AuthorizationRequestResolveEvent($authRequest) | ||
); | ||
|
||
if ($event->hasResponse()) { | ||
return $event->getResponse(); | ||
} | ||
|
||
$authRequest->setAuthorizationApproved($event->getAuthorizationResolution()); | ||
|
||
return $this->server->completeAuthorizationRequest($authRequest, $serverResponse); | ||
} catch (OAuthServerException $e) { | ||
return $e->generateHttpResponse($serverResponse); | ||
} | ||
} | ||
|
||
private function getUserEntity(): User | ||
{ | ||
$userEntity = new User(); | ||
|
||
$user = $this->security->getUser(); | ||
if ($user instanceof UserInterface) { | ||
$userEntity->setIdentifier($user->getUsername()); | ||
} | ||
|
||
return $userEntity; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\Event; | ||
|
||
use League\OAuth2\Server\Entities\ClientEntityInterface; | ||
use League\OAuth2\Server\Entities\ScopeEntityInterface; | ||
use League\OAuth2\Server\Entities\UserEntityInterface; | ||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest; | ||
use LogicException; | ||
use Psr\Http\Message\ResponseInterface; | ||
use Symfony\Component\EventDispatcher\Event; | ||
|
||
final class AuthorizationRequestResolveEvent extends Event | ||
{ | ||
public const AUTHORIZATION_APPROVED = true; | ||
public const AUTHORIZATION_DENIED = false; | ||
|
||
/** | ||
* @var AuthorizationRequest | ||
*/ | ||
private $authorizationRequest; | ||
|
||
/** | ||
* @var ResponseInterface|null | ||
*/ | ||
private $response; | ||
|
||
/** | ||
* @var bool | ||
*/ | ||
private $authorizationResolution = self::AUTHORIZATION_DENIED; | ||
|
||
public function __construct(AuthorizationRequest $authorizationRequest) | ||
{ | ||
$this->authorizationRequest = $authorizationRequest; | ||
} | ||
|
||
public function getAuthorizationResolution(): bool | ||
{ | ||
return $this->authorizationResolution; | ||
} | ||
|
||
public function resolveAuthorization(bool $authorizationResolution): void | ||
{ | ||
$this->authorizationResolution = $authorizationResolution; | ||
$this->response = null; | ||
} | ||
|
||
public function hasResponse(): bool | ||
{ | ||
return $this->response instanceof ResponseInterface; | ||
} | ||
|
||
public function getResponse(): ResponseInterface | ||
{ | ||
if (!$this->hasResponse()) { | ||
throw new LogicException('There is no response. You should call "hasResponse" to check if the response exists.'); | ||
} | ||
|
||
return $this->response; | ||
} | ||
|
||
public function setResponse(ResponseInterface $response): void | ||
{ | ||
$this->response = $response; | ||
} | ||
|
||
public function getGrantTypeId(): string | ||
{ | ||
return $this->authorizationRequest->getGrantTypeId(); | ||
} | ||
|
||
public function getClient(): ClientEntityInterface | ||
{ | ||
return $this->authorizationRequest->getClient(); | ||
} | ||
|
||
public function getUser(): UserEntityInterface | ||
{ | ||
return $this->authorizationRequest->getUser(); | ||
} | ||
|
||
/** | ||
* @return ScopeEntityInterface[] | ||
*/ | ||
public function getScopes(): array | ||
{ | ||
return $this->authorizationRequest->getScopes(); | ||
} | ||
|
||
public function isAuthorizationApproved(): bool | ||
{ | ||
return $this->authorizationRequest->isAuthorizationApproved(); | ||
} | ||
|
||
public function getRedirectUri(): ?string | ||
{ | ||
return $this->authorizationRequest->getRedirectUri(); | ||
} | ||
|
||
public function getState(): ?string | ||
{ | ||
return $this->authorizationRequest->getState(); | ||
} | ||
|
||
public function getCodeChallenge(): string | ||
{ | ||
return $this->authorizationRequest->getCodeChallenge(); | ||
} | ||
|
||
public function getCodeChallengeMethod(): string | ||
{ | ||
return $this->authorizationRequest->getCodeChallengeMethod(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\League\Entity; | ||
|
||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface; | ||
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait; | ||
use League\OAuth2\Server\Entities\Traits\EntityTrait; | ||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; | ||
|
||
final class AuthCode implements AuthCodeEntityInterface | ||
{ | ||
use AuthCodeTrait; | ||
use EntityTrait; | ||
use TokenEntityTrait; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\League\Repository; | ||
|
||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface; | ||
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; | ||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Converter\ScopeConverter; | ||
use Trikoder\Bundle\OAuth2Bundle\League\Entity\AuthCode; | ||
use Trikoder\Bundle\OAuth2Bundle\Manager\AuthorizationCodeManagerInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Model\AuthorizationCode; | ||
|
||
final class AuthCodeRepository implements AuthCodeRepositoryInterface | ||
{ | ||
/** | ||
* @var AuthorizationCodeManagerInterface | ||
*/ | ||
private $authorizationCodeManager; | ||
|
||
/** | ||
* @var ClientManagerInterface | ||
*/ | ||
private $clientManager; | ||
|
||
/** | ||
* @var ScopeConverter | ||
*/ | ||
private $scopeConverter; | ||
|
||
public function __construct( | ||
AuthorizationCodeManagerInterface $authorizationCodeManager, | ||
ClientManagerInterface $clientManager, | ||
ScopeConverter $scopeConverter | ||
) { | ||
$this->authorizationCodeManager = $authorizationCodeManager; | ||
$this->clientManager = $clientManager; | ||
$this->scopeConverter = $scopeConverter; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getNewAuthCode() | ||
{ | ||
return new AuthCode(); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function persistNewAuthCode(AuthCodeEntityInterface $authCode) | ||
{ | ||
$authorizationCode = $this->authorizationCodeManager->find($authCode->getIdentifier()); | ||
|
||
if (null !== $authorizationCode) { | ||
throw UniqueTokenIdentifierConstraintViolationException::create(); | ||
} | ||
|
||
$authorizationCode = $this->buildAuthorizationCode($authCode); | ||
|
||
$this->authorizationCodeManager->save($authorizationCode); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function revokeAuthCode($codeId) | ||
{ | ||
$authorizationCode = $this->authorizationCodeManager->find($codeId); | ||
|
||
if (null === $codeId) { | ||
return; | ||
} | ||
|
||
$authorizationCode->revoke(); | ||
|
||
$this->authorizationCodeManager->save($authorizationCode); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function isAuthCodeRevoked($codeId) | ||
{ | ||
$authorizationCode = $this->authorizationCodeManager->find($codeId); | ||
|
||
if (null === $authorizationCode) { | ||
return true; | ||
} | ||
|
||
return $authorizationCode->isRevoked(); | ||
} | ||
|
||
private function buildAuthorizationCode(AuthCode $authCode): AuthorizationCode | ||
{ | ||
$client = $this->clientManager->find($authCode->getClient()->getIdentifier()); | ||
|
||
$authorizationCode = new AuthorizationCode( | ||
$authCode->getIdentifier(), | ||
$authCode->getExpiryDateTime(), | ||
$client, | ||
$authCode->getUserIdentifier(), | ||
$this->scopeConverter->toDomainArray($authCode->getScopes()) | ||
); | ||
|
||
return $authorizationCode; | ||
} | ||
} |
Oops, something went wrong.