Skip to content

Commit

Permalink
feature #49 add request token event (jr-k)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 0.1-dev branch.

Discussion
----------

add request token event

I've added an event to manipulate the response during /token process. Useful to add some Set-Cookie directives for example.

Commits
-------

7be39ea add request token event
  • Loading branch information
chalasr committed Oct 5, 2021
2 parents ffbc931 + 7be39ea commit df405a8
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 2 deletions.
22 changes: 20 additions & 2 deletions src/Controller/TokenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

namespace League\Bundle\OAuth2ServerBundle\Controller;

use League\Bundle\OAuth2ServerBundle\Event\TokenRequestResolveEvent;
use League\Bundle\OAuth2ServerBundle\OAuth2Events;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Exception\OAuthServerException;
use Psr\Http\Message\ResponseFactoryInterface;
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

final class TokenController
{
Expand All @@ -34,16 +37,23 @@ final class TokenController
*/
private $responseFactory;

/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;

public function __construct(
AuthorizationServer $server,
HttpMessageFactoryInterface $httpMessageFactory,
HttpFoundationFactoryInterface $httpFoundationFactory,
ResponseFactoryInterface $responseFactory
ResponseFactoryInterface $responseFactory,
EventDispatcherInterface $eventDispatcher
) {
$this->server = $server;
$this->httpMessageFactory = $httpMessageFactory;
$this->httpFoundationFactory = $httpFoundationFactory;
$this->responseFactory = $responseFactory;
$this->eventDispatcher = $eventDispatcher;
}

public function indexAction(Request $request): Response
Expand All @@ -57,6 +67,14 @@ public function indexAction(Request $request): Response
$response = $e->generateHttpResponse($serverResponse);
}

return $this->httpFoundationFactory->createResponse($response);
$renderedResponse = $this->httpFoundationFactory->createResponse($response);

/** @var TokenRequestResolveEvent $event */
$this->eventDispatcher->dispatch(
new TokenRequestResolveEvent($renderedResponse),
OAuth2Events::TOKEN_REQUEST_RESOLVE
);

return $renderedResponse;
}
}
33 changes: 33 additions & 0 deletions src/Event/TokenRequestResolveEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace League\Bundle\OAuth2ServerBundle\Event;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\Event;

final class TokenRequestResolveEvent extends Event
{
/**
* @var Response
*/
private $response;

public function __construct(Response $response)
{
$this->response = $response;
}

public function getResponse(): Response
{
return $this->response;
}

public function setResponse(Response $response): self
{
$this->response = $response;

return $this;
}
}
8 changes: 8 additions & 0 deletions src/OAuth2Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ final class OAuth2Events
*/
public const AUTHORIZATION_REQUEST_RESOLVE = 'league.oauth2_server.event.authorization_request_resolve';

/**
* The REQUEST_TOKEN_RESOLVE event occurs right before the system
* complete token request.
*
* You could manipulate the response.
*/
public const TOKEN_REQUEST_RESOLVE = 'league.oauth2_server.event.token_request_resolve';

/**
* The PRE_SAVE_CLIENT event occurs right before the client is saved
* by a ClientManager.
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@
service('league.oauth2_server.factory.psr_http'),
service('league.oauth2_server.factory.http_foundation'),
service('league.oauth2_server.factory.psr17'),
service('event_dispatcher'),
])
->tag('controller.service_arguments')
->alias(TokenController::class, 'league.oauth2_server.controller.token')
Expand Down
49 changes: 49 additions & 0 deletions tests/Acceptance/TokenEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace League\Bundle\OAuth2ServerBundle\Tests\Acceptance;

use League\Bundle\OAuth2ServerBundle\Event\TokenRequestResolveEvent;
use League\Bundle\OAuth2ServerBundle\Event\UserResolveEvent;
use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface;
use League\Bundle\OAuth2ServerBundle\Manager\AuthorizationCodeManagerInterface;
Expand Down Expand Up @@ -37,6 +38,13 @@ public function testSuccessfulClientCredentialsRequest(): void
'grant_type' => 'client_credentials',
]);

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$response = $this->client->getResponse();

$this->assertSame(200, $response->getStatusCode());
Expand All @@ -48,6 +56,7 @@ public function testSuccessfulClientCredentialsRequest(): void
$this->assertLessThanOrEqual(3600, $jsonResponse['expires_in']);
$this->assertGreaterThan(0, $jsonResponse['expires_in']);
$this->assertNotEmpty($jsonResponse['access_token']);
$this->assertEmpty($response->headers->get('foo'), 'bar');
}

public function testSuccessfulPasswordRequest(): void
Expand All @@ -59,6 +68,13 @@ public function testSuccessfulPasswordRequest(): void
$event->setUser(FixtureFactory::createUser());
});

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$this->client->request('POST', '/token', [
'client_id' => 'foo',
'client_secret' => 'secret',
Expand All @@ -79,6 +95,7 @@ public function testSuccessfulPasswordRequest(): void
$this->assertGreaterThan(0, $jsonResponse['expires_in']);
$this->assertNotEmpty($jsonResponse['access_token']);
$this->assertNotEmpty($jsonResponse['refresh_token']);
$this->assertSame($response->headers->get('foo'), 'bar');
}

public function testSuccessfulRefreshTokenRequest(): void
Expand All @@ -95,6 +112,13 @@ public function testSuccessfulRefreshTokenRequest(): void
'refresh_token' => TestHelper::generateEncryptedPayload($refreshToken),
]);

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$response = $this->client->getResponse();

$this->assertSame(200, $response->getStatusCode());
Expand All @@ -107,6 +131,7 @@ public function testSuccessfulRefreshTokenRequest(): void
$this->assertGreaterThan(0, $jsonResponse['expires_in']);
$this->assertNotEmpty($jsonResponse['access_token']);
$this->assertNotEmpty($jsonResponse['refresh_token']);
$this->assertEmpty($response->headers->get('foo'), 'bar');
}

public function testSuccessfulAuthorizationCodeRequest(): void
Expand All @@ -124,6 +149,13 @@ public function testSuccessfulAuthorizationCodeRequest(): void
'code' => TestHelper::generateEncryptedAuthCodePayload($authCode),
]);

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$response = $this->client->getResponse();

$this->assertSame(200, $response->getStatusCode());
Expand All @@ -135,6 +167,7 @@ public function testSuccessfulAuthorizationCodeRequest(): void
$this->assertLessThanOrEqual(3600, $jsonResponse['expires_in']);
$this->assertGreaterThan(0, $jsonResponse['expires_in']);
$this->assertNotEmpty($jsonResponse['access_token']);
$this->assertEmpty($response->headers->get('foo'), 'bar');
}

public function testSuccessfulAuthorizationCodeRequestWithPublicClient(): void
Expand All @@ -144,6 +177,13 @@ public function testSuccessfulAuthorizationCodeRequestWithPublicClient(): void
->get(AuthorizationCodeManagerInterface::class)
->find(FixtureFactory::FIXTURE_AUTH_CODE_PUBLIC_CLIENT);

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$this->client->request('POST', '/token', [
'client_id' => FixtureFactory::FIXTURE_PUBLIC_CLIENT,
'grant_type' => 'authorization_code',
Expand All @@ -162,6 +202,7 @@ public function testSuccessfulAuthorizationCodeRequestWithPublicClient(): void
$this->assertLessThanOrEqual(3600, $jsonResponse['expires_in']);
$this->assertGreaterThan(0, $jsonResponse['expires_in']);
$this->assertNotEmpty($jsonResponse['access_token']);
$this->assertSame($response->headers->get('foo'), 'bar');
}

public function testFailedTokenRequest(): void
Expand All @@ -188,6 +229,13 @@ public function testFailedClientCredentialsTokenRequest(): void
'grant_type' => 'client_credentials',
]);

$this->client
->getContainer()
->get('event_dispatcher')
->addListener(OAuth2Events::TOKEN_REQUEST_RESOLVE, static function (TokenRequestResolveEvent $event): void {
$event->getResponse()->headers->set('foo', 'bar');
});

$response = $this->client->getResponse();

$this->assertSame(401, $response->getStatusCode());
Expand All @@ -197,5 +245,6 @@ public function testFailedClientCredentialsTokenRequest(): void

$this->assertSame('invalid_client', $jsonResponse['error']);
$this->assertSame('Client authentication failed', $jsonResponse['message']);
$this->assertEmpty($response->headers->get('foo'), 'bar');
}
}

0 comments on commit df405a8

Please sign in to comment.