Skip to content

Commit 01e1425

Browse files
Password Grant
1 parent 2a4d30c commit 01e1425

File tree

21 files changed

+437
-4
lines changed

21 files changed

+437
-4
lines changed

.env.dist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ APP_SECRET=cc3d4aecd8aa414ca1cfc969839807f4
1515
# Configure your db driver and server_version in config/packages/doctrine.yaml
1616
DATABASE_URL=mysql://db_user:[email protected]:3306/db_name
1717
###< doctrine/doctrine-bundle ###
18+
19+
###> oAuth2 Server ###
20+
OAUTH2_PRIVATE_KEY=/application/private.key
21+
OAUTH2_PUBLIC_KEY=/application/public.key
22+
OAUTH2_ENCRYPTION_KEY=
23+
###< oAuth2 Server ###

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
"symfony/flex": "^1.1",
1313
"symfony/framework-bundle": "*",
1414
"symfony/orm-pack": "^1.0",
15+
"symfony/psr-http-message-bridge": "^1.1",
1516
"symfony/security-bundle": "*",
16-
"symfony/yaml": "*"
17+
"symfony/yaml": "*",
18+
"zendframework/zend-diactoros": "^2.0"
1719
},
1820
"require-dev": {
1921
"symfony/dotenv": "*"

composer.lock

Lines changed: 180 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/services.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,21 @@ services:
2828

2929
# add more service definitions when explicit configuration is needed
3030
# please note that last definitions always *replace* previous ones
31+
32+
League\OAuth2\Server\AuthorizationServer:
33+
arguments:
34+
$clientRepository: '@App\Infrastructure\oAuth2Server\Bridge\ClientRepository'
35+
$accessTokenRepository: '@App\Infrastructure\oAuth2Server\Bridge\AccessTokenRepository'
36+
$scopeRepository: '@App\Infrastructure\oAuth2Server\Bridge\ScopeRepository'
37+
$privateKey: '%env(OAUTH2_PRIVATE_KEY)%'
38+
$encryptionKey: '%env(OAUTH2_ENCRYPTION_KEY)%'
39+
40+
League\OAuth2\Server\Grant\PasswordGrant:
41+
arguments:
42+
$userRepository: '@App\Infrastructure\oAuth2Server\Bridge\UserRepository'
43+
$refreshTokenRepository: '@App\Infrastructure\oAuth2Server\Bridge\RefreshTokenRepository'
44+
45+
League\OAuth2\Server\ResourceServer:
46+
arguments:
47+
$accessTokenRepository: '@App\Infrastructure\oAuth2Server\Bridge\AccessTokenRepository'
48+
$publicKey: '%env(OAUTH2_PUBLIC_KEY)%'
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
namespace App\Application\EventSubscriber;
4+
5+
use App\Presentation\Api\Rest\Controller\TokenAuthenticatedController;
6+
use League\OAuth2\Server\Exception\OAuthServerException;
7+
use League\OAuth2\Server\ResourceServer;
8+
use Psr\Http\Message\ServerRequestInterface;
9+
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
10+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11+
use Symfony\Component\HttpFoundation\JsonResponse;
12+
use Symfony\Component\HttpFoundation\Request;
13+
use Symfony\Component\HttpFoundation\Response;
14+
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
15+
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
16+
use Symfony\Component\HttpKernel\KernelEvents;
17+
18+
final class TokenSubscriber implements EventSubscriberInterface
19+
{
20+
/**
21+
* @var ResourceServer
22+
*/
23+
private $resourceServer;
24+
25+
/**
26+
* TokenSubscriber constructor.
27+
* @param ResourceServer $resourceServer
28+
*/
29+
public function __construct(ResourceServer $resourceServer)
30+
{
31+
$this->resourceServer = $resourceServer;
32+
}
33+
34+
/**
35+
* @return array
36+
*/
37+
public static function getSubscribedEvents(): array
38+
{
39+
return [
40+
KernelEvents::CONTROLLER => 'onKernelController',
41+
KernelEvents::EXCEPTION => 'onKernelException'
42+
];
43+
}
44+
45+
/**
46+
* @param FilterControllerEvent $event
47+
* @throws OAuthServerException
48+
*/
49+
public function onKernelController(FilterControllerEvent $event): void
50+
{
51+
$controller = $event->getController();
52+
53+
/*
54+
* $controller passed can be either a class or a Closure.
55+
* This is not usual in Symfony but it may happen.
56+
* If it is a class, it comes in array format
57+
*/
58+
if (!\is_array($controller)) {
59+
return;
60+
}
61+
62+
if ($controller[0] instanceof TokenAuthenticatedController) {
63+
$request = $event->getRequest();
64+
$psrRequest = (new DiactorosFactory)->createRequest($request);
65+
try {
66+
$psrRequest = $this->resourceServer->validateAuthenticatedRequest($psrRequest);
67+
} catch (OAuthServerException $exception) {
68+
throw $exception;
69+
} catch (\Exception $exception) {
70+
throw new OAuthServerException($exception->getMessage(), 0, 'unknown_error', Response::HTTP_INTERNAL_SERVER_ERROR);
71+
}
72+
73+
$this->enrichSymfonyRequestWithAuthData($request, $psrRequest);
74+
}
75+
}
76+
77+
/**
78+
* @param Request $request
79+
* @param ServerRequestInterface $psrRequest
80+
*/
81+
private function enrichSymfonyRequestWithAuthData(Request $request, ServerRequestInterface $psrRequest): void
82+
{
83+
$request = $request->request;
84+
$requestArray = $request->all();
85+
$requestArray['oauth_user_id'] = $psrRequest->getAttribute('oauth_user_id');
86+
$requestArray['oauth_access_token_id'] = $psrRequest->getAttribute('oauth_access_token_id');
87+
$requestArray['oauth_client_id'] = $psrRequest->getAttribute('oauth_client_id');
88+
$request->replace($requestArray);
89+
}
90+
91+
/**
92+
* @param GetResponseForExceptionEvent $event
93+
*/
94+
public function onKernelException(GetResponseForExceptionEvent $event): void
95+
{
96+
$exception = $event->getException();
97+
98+
if (!($exception instanceof OAuthServerException)) {
99+
return;
100+
}
101+
102+
$response = new JsonResponse(['error' => $exception->getMessage()], $exception->getHttpStatusCode());
103+
$event->setResponse($response);
104+
}
105+
}

src/Application/Repository/Doctrine/RefreshTokenRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
namespace App\Application\Repository\Doctrine;
44

55
use App\Domain\Model\RefreshToken;
6-
use App\Domain\Repository\AccessTokenRepositoryInterface;
6+
use App\Domain\Repository\RefreshTokenRepositoryInterface;
77
use Doctrine\Common\Persistence\ObjectRepository;
88
use Doctrine\ORM\EntityManagerInterface;
99

10-
final class RefreshTokenRepository implements AccessTokenRepositoryInterface
10+
final class RefreshTokenRepository implements RefreshTokenRepositoryInterface
1111
{
1212
private const ENTITY = RefreshToken::class;
1313

0 commit comments

Comments
 (0)