Skip to content

Commit

Permalink
Create a request extractor API to replace the static method for extra…
Browse files Browse the repository at this point in the history
…cting the refresh token from the request
  • Loading branch information
mbabker committed Jul 13, 2021
1 parent a30e372 commit 1fc313c
Show file tree
Hide file tree
Showing 22 changed files with 587 additions and 254 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## Unreleased

- Added `Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface` as an interface for extracting the refresh token from the request, implementations provided by this bundle include:
- `Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ChainExtractor` - Calls all registered extractors to find the request token (by default, this extractor is aliased to the interface in the DI container)
- `Gesdinet\JWTRefreshTokenBundle\Request\Extractor\RequestBodyExtractor` - Decodes a JSON request body and loads the token from it
- `Gesdinet\JWTRefreshTokenBundle\Request\Extractor\RequestParameterExtractor` - Loads the refresh token by calling `$request->get()`
- Removed the `Gesdinet\JWTRefreshTokenBundle\Request\RequestRefreshToken` class, a `Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface` implementation should be used instead
25 changes: 25 additions & 0 deletions DependencyInjection/Compiler/AddExtractorsToChainCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Gesdinet\JWTRefreshTokenBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class AddExtractorsToChainCompilerPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;

public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('gesdinet.jwtrefreshtoken.request.extractor.chain')) {
return;
}

$definition = $container->getDefinition('gesdinet.jwtrefreshtoken.request.extractor.chain');

foreach ($this->findAndSortTaggedServices('gesdinet_jwt_refresh_token.request_extractor', $container) as $extractorService) {
$definition->addMethodCall('addExtractor', [$extractorService]);
}
}
}
3 changes: 3 additions & 0 deletions DependencyInjection/GesdinetJWTRefreshTokenExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Gesdinet\JWTRefreshTokenBundle\DependencyInjection;

use Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Definition;
Expand Down Expand Up @@ -40,6 +41,8 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new Loader\PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.php');

$container->registerForAutoconfiguration(ExtractorInterface::class)->addTag('gesdinet_jwt_refresh_token.request_extractor');

$container->setParameter('gesdinet_jwt_refresh_token.ttl', $config['ttl']);
$container->setParameter('gesdinet_jwt_refresh_token.ttl_update', $config['ttl_update']);
$container->setParameter('gesdinet_jwt_refresh_token.security.firewall', $config['firewall']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
];

$container->setDefinition($authenticatorId, new ChildDefinition('gesdinet.jwtrefreshtoken.security.refresh_token_authenticator'))
->addArgument(new Reference($userProviderId))
->addArgument(new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)))
->addArgument(new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)))
->addArgument($options);
->replaceArgument(3, new Reference($userProviderId))
->replaceArgument(4, new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)))
->replaceArgument(5, new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)))
->replaceArgument(6, $options);

return $authenticatorId;
}
Expand Down
20 changes: 13 additions & 7 deletions EventListener/AttachRefreshTokenOnSuccessListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Gesdinet\JWTRefreshTokenBundle\Generator\RefreshTokenGeneratorInterface;
use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenInterface;
use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenManagerInterface;
use Gesdinet\JWTRefreshTokenBundle\Request\RequestRefreshToken;
use Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\User\UserInterface;
Expand Down Expand Up @@ -52,8 +52,11 @@ class AttachRefreshTokenOnSuccessListener
protected $refreshTokenGenerator;

/**
* AttachRefreshTokenOnSuccessListener constructor.
*
* @var ExtractorInterface
*/
protected $extractor;

/**
* @param int $ttl
* @param string $tokenParameterName
* @param bool $singleUse
Expand All @@ -64,27 +67,30 @@ public function __construct(
RequestStack $requestStack,
$tokenParameterName,
$singleUse,
RefreshTokenGeneratorInterface $refreshTokenGenerator
RefreshTokenGeneratorInterface $refreshTokenGenerator,
ExtractorInterface $extractor
) {
$this->refreshTokenManager = $refreshTokenManager;
$this->ttl = $ttl;
$this->requestStack = $requestStack;
$this->tokenParameterName = $tokenParameterName;
$this->singleUse = $singleUse;
$this->refreshTokenGenerator = $refreshTokenGenerator;
$this->extractor = $extractor;
}

public function attachRefreshToken(AuthenticationSuccessEvent $event)
{
$data = $event->getData();
$user = $event->getUser();
$request = $this->requestStack->getCurrentRequest();

if (!$user instanceof UserInterface) {
return;
}

$refreshTokenString = RequestRefreshToken::getRefreshToken($request, $this->tokenParameterName);
$data = $event->getData();
$request = $this->requestStack->getCurrentRequest();

$refreshTokenString = $this->extractor->getRefreshToken($request, $this->tokenParameterName);

if ($refreshTokenString && true === $this->singleUse) {
$refreshToken = $this->refreshTokenManager->get($refreshTokenString);
Expand Down
2 changes: 2 additions & 0 deletions GesdinetJWTRefreshTokenBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Gesdinet\JWTRefreshTokenBundle;

use Gesdinet\JWTRefreshTokenBundle\DependencyInjection\Compiler\AddExtractorsToChainCompilerPass;
use Gesdinet\JWTRefreshTokenBundle\DependencyInjection\Compiler\CustomUserProviderCompilerPass;
use Gesdinet\JWTRefreshTokenBundle\DependencyInjection\Compiler\ObjectManagerCompilerPass;
use Gesdinet\JWTRefreshTokenBundle\DependencyInjection\Compiler\UserCheckerCompilerPass;
Expand All @@ -17,6 +18,7 @@ public function build(ContainerBuilder $container)
{
parent::build($container);

$container->addCompilerPass(new AddExtractorsToChainCompilerPass());
$container->addCompilerPass(new CustomUserProviderCompilerPass(true));
$container->addCompilerPass(new ObjectManagerCompilerPass());
$container->addCompilerPass(new UserCheckerCompilerPass(true));
Expand Down
Loading

0 comments on commit 1fc313c

Please sign in to comment.