-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from ajgarlag/feature/authorization_code
Add support for the "authorization_code" grant type
- Loading branch information
Showing
33 changed files
with
1,428 additions
and
44 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,74 @@ | ||
<?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 Trikoder\Bundle\OAuth2Bundle\Converter\UserConverter; | ||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent; | ||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEventFactory; | ||
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events; | ||
|
||
final class AuthorizationController | ||
{ | ||
/** | ||
* @var AuthorizationServer | ||
*/ | ||
private $server; | ||
|
||
/** | ||
* @var EventDispatcherInterface | ||
*/ | ||
private $eventDispatcher; | ||
|
||
/** | ||
* @var AuthorizationRequestResolveEventFactory | ||
*/ | ||
private $eventFactory; | ||
|
||
/** | ||
* @var UserConverter | ||
*/ | ||
private $userConverter; | ||
|
||
public function __construct(AuthorizationServer $server, EventDispatcherInterface $eventDispatcher, AuthorizationRequestResolveEventFactory $eventFactory, UserConverter $userConverter) | ||
{ | ||
$this->server = $server; | ||
$this->eventDispatcher = $eventDispatcher; | ||
$this->eventFactory = $eventFactory; | ||
$this->userConverter = $userConverter; | ||
} | ||
|
||
public function indexAction(ServerRequestInterface $serverRequest, ResponseFactoryInterface $responseFactory): ResponseInterface | ||
{ | ||
$serverResponse = $responseFactory->createResponse(); | ||
|
||
try { | ||
$authRequest = $this->server->validateAuthorizationRequest($serverRequest); | ||
|
||
/** @var AuthorizationRequestResolveEvent $event */ | ||
$event = $this->eventDispatcher->dispatch( | ||
OAuth2Events::AUTHORIZATION_REQUEST_RESOLVE, | ||
$this->eventFactory->fromAuthorizationRequest($authRequest) | ||
); | ||
|
||
$authRequest->setUser($this->userConverter->toLeague($event->getUser())); | ||
|
||
if ($event->hasResponse()) { | ||
return $event->getResponse(); | ||
} | ||
|
||
$authRequest->setAuthorizationApproved($event->getAuthorizationResolution()); | ||
|
||
return $this->server->completeAuthorizationRequest($authRequest, $serverResponse); | ||
} catch (OAuthServerException $e) { | ||
return $e->generateHttpResponse($serverResponse); | ||
} | ||
} | ||
} |
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,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\Converter; | ||
|
||
use League\OAuth2\Server\Entities\UserEntityInterface; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\League\Entity\User; | ||
|
||
final class UserConverter | ||
{ | ||
public function toLeague(UserInterface $user = null): UserEntityInterface | ||
{ | ||
$userEntity = new User(); | ||
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,159 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\Event; | ||
|
||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest; | ||
use LogicException; | ||
use Psr\Http\Message\ResponseInterface; | ||
use RuntimeException; | ||
use Symfony\Component\EventDispatcher\Event; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Converter\ScopeConverter; | ||
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Model\Client; | ||
use Trikoder\Bundle\OAuth2Bundle\Model\Scope; | ||
|
||
final class AuthorizationRequestResolveEvent extends Event | ||
{ | ||
public const AUTHORIZATION_APPROVED = true; | ||
public const AUTHORIZATION_DENIED = false; | ||
|
||
/** | ||
* @var AuthorizationRequest | ||
*/ | ||
private $authorizationRequest; | ||
|
||
/** | ||
* @var ScopeConverter | ||
*/ | ||
private $scopeConverter; | ||
|
||
/** | ||
* @var ClientManagerInterface | ||
*/ | ||
private $clientManager; | ||
|
||
/** | ||
* @var bool | ||
*/ | ||
private $authorizationResolution = self::AUTHORIZATION_DENIED; | ||
|
||
/** | ||
* @var ResponseInterface|null | ||
*/ | ||
private $response; | ||
|
||
/** | ||
* @var UserInterface|null | ||
*/ | ||
private $user; | ||
|
||
public function __construct(AuthorizationRequest $authorizationRequest, ScopeConverter $scopeConverter, ClientManagerInterface $clientManager) | ||
{ | ||
$this->authorizationRequest = $authorizationRequest; | ||
$this->scopeConverter = $scopeConverter; | ||
$this->clientManager = $clientManager; | ||
} | ||
|
||
public function getAuthorizationResolution(): bool | ||
{ | ||
return $this->authorizationResolution; | ||
} | ||
|
||
public function resolveAuthorization(bool $authorizationResolution): self | ||
{ | ||
$this->authorizationResolution = $authorizationResolution; | ||
$this->response = null; | ||
$this->stopPropagation(); | ||
|
||
return $this; | ||
} | ||
|
||
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): self | ||
{ | ||
$this->response = $response; | ||
$this->stopPropagation(); | ||
|
||
return $this; | ||
} | ||
|
||
public function getGrantTypeId(): string | ||
{ | ||
return $this->authorizationRequest->getGrantTypeId(); | ||
} | ||
|
||
public function getClient(): Client | ||
{ | ||
$identifier = $this->authorizationRequest->getClient()->getIdentifier(); | ||
$client = $this->clientManager->find($identifier); | ||
|
||
if (null === $client) { | ||
throw new RuntimeException(sprintf('No client found for the given identifier "%s".', $identifier)); | ||
} | ||
|
||
return $client; | ||
} | ||
|
||
public function getUser(): ?UserInterface | ||
{ | ||
return $this->user; | ||
} | ||
|
||
public function setUser(?UserInterface $user): self | ||
{ | ||
$this->user = $user; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @return Scope[] | ||
*/ | ||
public function getScopes(): array | ||
{ | ||
return $this->scopeConverter->toDomainArray( | ||
$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,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\Event; | ||
|
||
use League\OAuth2\Server\RequestTypes\AuthorizationRequest; | ||
use Trikoder\Bundle\OAuth2Bundle\Converter\ScopeConverter; | ||
use Trikoder\Bundle\OAuth2Bundle\Manager\ClientManagerInterface; | ||
|
||
class AuthorizationRequestResolveEventFactory | ||
{ | ||
/** | ||
* @var ScopeConverter | ||
*/ | ||
private $scopeConverter; | ||
|
||
/** | ||
* @var ClientManagerInterface | ||
*/ | ||
private $clientManager; | ||
|
||
public function __construct(ScopeConverter $scopeConverter, ClientManagerInterface $clientManager) | ||
{ | ||
$this->scopeConverter = $scopeConverter; | ||
$this->clientManager = $clientManager; | ||
} | ||
|
||
public function fromAuthorizationRequest(AuthorizationRequest $authorizationRequest): AuthorizationRequestResolveEvent | ||
{ | ||
return new AuthorizationRequestResolveEvent($authorizationRequest, $this->scopeConverter, $this->clientManager); | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
EventListener/AuthorizationRequestUserResolvingListener.php
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,38 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Trikoder\Bundle\OAuth2Bundle\EventListener; | ||
|
||
use Symfony\Component\Security\Core\Security; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent; | ||
|
||
/** | ||
* Class AuthorizationRequestUserResolvingListener | ||
* | ||
* Listener sets currently authenticated user to authorization request context | ||
*/ | ||
class AuthorizationRequestUserResolvingListener | ||
{ | ||
/** | ||
* @var Security | ||
*/ | ||
private $security; | ||
|
||
/** | ||
* AuthorizationRequestUserResolvingListener constructor. | ||
*/ | ||
public function __construct(Security $security) | ||
{ | ||
$this->security = $security; | ||
} | ||
|
||
public function onAuthorizationRequest(AuthorizationRequestResolveEvent $event) | ||
{ | ||
$user = $this->security->getUser(); | ||
if ($user instanceof UserInterface) { | ||
$event->setUser($user); | ||
} | ||
} | ||
} |
Oops, something went wrong.