Skip to content

Commit

Permalink
Fix Symfony 5.3 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
chalasr committed Nov 1, 2021
1 parent cafbc6c commit 82a0e67
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 86 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ jobs:
symfony: 4.4.*
composer-flags: '--prefer-stable'
can-fail: false
# Development Symfony branches
- php: 7.3
symfony: 5.4.*@dev
symfony: 5.3.*
composer-flags: '--prefer-stable' # Needed to force `lcobucci/jwt` to install a usable version
can-fail: false
# Development Symfony branches
- php: 7.4
symfony: 5.4.*@dev
composer-flags: ''
Expand Down
105 changes: 41 additions & 64 deletions DependencyInjection/Security/Factory/JWTAuthenticatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,74 +3,51 @@
namespace Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory;

use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;

/**
* Wires the "jwt" authenticator from user configuration.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class JWTAuthenticatorFactory implements AuthenticatorFactoryInterface
{
/**
* @throws \LogicException
*/
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
throw new \LogicException('This method is implemented for BC purpose and should never be called.');
}

/**
* {@inheritdoc}
*/
public function getPriority(): int
{
return -10;
}

/**
* {@inheritdoc}
*/
public function getKey(): string
{
return 'jwt';
}
if (interface_exists(SecurityFactoryInterface::class) && !interface_exists(AuthenticatorFactoryInterface::class)) {
eval('
namespace Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
/**
* Wires the "jwt" authenticator from user configuration.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class JWTAuthenticatorFactory implements SecurityFactoryInterface
{
use JWTAuthenticatorFactoryTrait;
}
');
} elseif (!method_exists(SecurityExtension::class, 'addAuthenticatorFactory')) {
eval('
namespace Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
/**
* Wires the "jwt" authenticator from user configuration.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class JWTAuthenticatorFactory implements AuthenticatorFactoryInterface, SecurityFactoryInterface
{
use JWTAuthenticatorFactoryTrait;
}
');
} else {
/**
* {@inheritdoc}
* Wires the "jwt" authenticator from user configuration.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
public function addConfiguration(NodeDefinition $node)
class JWTAuthenticatorFactory implements AuthenticatorFactoryInterface
{
$node
->children()
->scalarNode('provider')
->defaultNull()
->end()
->scalarNode('authenticator')
->defaultValue('lexik_jwt_authentication.security.jwt_authenticator')
->end()
->end()
;
}

public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
{
$authenticatorId = 'security.authenticator.jwt.'.$firewallName;

$userProviderId = empty($config['provider']) ? $userProviderId : 'security.user.provider.concrete.' . $config['provider'];

$container
->setDefinition($authenticatorId, new ChildDefinition($config['authenticator']))
->replaceArgument(3, new Reference($userProviderId))
;

// Compile-time parameter removed by RemoveLegacyAuthenticatorPass
// Stop setting it when guard support gets removed (aka when removing Symfony<5.3 support)
$container->setParameter('lexik_jwt_authentication.authenticator_manager_enabled', true);

return $authenticatorId;
use JWTAuthenticatorFactoryTrait;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory;

use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Wires the "jwt" authenticator from user configuration.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
trait JWTAuthenticatorFactoryTrait
{
/**
* @throws \LogicException
*
* @return array
*/
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
throw new \LogicException('This method is implemented for BC purpose and should never be called.');
}

/**
* {@inheritdoc}
*/
public function getPriority(): int
{
return -10;
}

public function getPosition(): string
{
return 'pre_auth';
}

/**
* {@inheritdoc}
*/
public function getKey(): string
{
return 'jwt';
}

/**
* {@inheritdoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('provider')
->defaultNull()
->end()
->scalarNode('authenticator')
->defaultValue('lexik_jwt_authentication.security.jwt_authenticator')
->end()
->end()
;
}

public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
{
$authenticatorId = 'security.authenticator.jwt.'.$firewallName;

$userProviderId = empty($config['provider']) ? $userProviderId : 'security.user.provider.concrete.' . $config['provider'];

$container
->setDefinition($authenticatorId, new ChildDefinition($config['authenticator']))
->replaceArgument(3, new Reference($userProviderId))
;

// Compile-time parameter removed by RemoveLegacyAuthenticatorPass
// Stop setting it when guard support gets removed (aka when removing Symfony<5.3 support)
$container->setParameter('lexik_jwt_authentication.authenticator_manager_enabled', true);

return $authenticatorId;
}
}
12 changes: 11 additions & 1 deletion LexikJWTAuthenticationBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory\JWTSecurityFactory;
use Lexik\Bundle\JWTAuthenticationBundle\DependencyInjection\Security\Factory\JWTUserFactory;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
use Symfony\Component\Console\Application;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -40,9 +41,18 @@ public function build(ContainerBuilder $container)
// Authenticator factory for Symfony 5.4 and later
if (method_exists($extension, 'addAuthenticatorFactory')) {
$extension->addAuthenticatorFactory(new JWTAuthenticatorFactory());

return;
}

// Security listener factory for Symfony 5.3 and earlier
if (method_exists($extension, 'addSecurityListenerFactory')) {
$extension->addSecurityListenerFactory(new JWTAuthenticatorFactory());

return;
}

// Security listener factory for Symfony 5.4 and earlier
// Security listener factory for Symfony 4.4
if (method_exists($extension, 'addSecurityListenerFactory')) {
$extension->addSecurityListenerFactory(new JWTFactory(false)); // BC 1.x, to be removed in 3.0
}
Expand Down
41 changes: 41 additions & 0 deletions Security/Authenticator/ForwardCompatAuthenticatorTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Lexik\Bundle\JWTAuthenticationBundle\Security\Authenticator;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;

$r = new \ReflectionMethod(AuthenticatorInterface::class, 'authenticate');

if ($r->hasReturnType() && Passport::class === $r->getReturnType()->getName()) {
eval('
namespace Lexik\Bundle\JWTAuthenticationBundle\Security\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
/**
* @internal
*/
trait ForwardCompatAuthenticatorTrait
{
public function authenticate(Request $request): Passport
{
return $this->doAuthenticate($request);
}
}
');
} else {
/**
* @internal
*/
trait ForwardCompatAuthenticatorTrait
{
public function authenticate(Request $request): PassportInterface
{
return $this->doAuthenticate($request);
}
}
}
4 changes: 3 additions & 1 deletion Security/Authenticator/JWTAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

class JWTAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface
{
use ForwardCompatAuthenticatorTrait;

/**
* @var TokenExtractorInterface
*/
Expand Down Expand Up @@ -91,7 +93,7 @@ public function supports(Request $request): ?bool
/**
* @return Passport
*/
public function authenticate(Request $request) /*: Passport */
public function doAuthenticate(Request $request) /*: Passport */
{
$token = $this->getTokenExtractor()->extract($request);

Expand Down
36 changes: 18 additions & 18 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,27 @@
"ext-openssl": "*",
"lcobucci/jwt": "^3.4|^4.0",
"namshi/jose": "^7.2",
"symfony/config": "^4.4|^5.4|^6.0",
"symfony/dependency-injection": "^4.4|^5.4|^6.0",
"symfony/config": "^4.4|^5.3|^6.0",
"symfony/dependency-injection": "^4.4|^5.3|^6.0",
"symfony/deprecation-contracts": "^2.4",
"symfony/event-dispatcher": "^4.4|^5.4|^6.0",
"symfony/http-foundation": "^4.4|^5.4|^6.0",
"symfony/http-kernel": "^4.4|^5.4|^6.0",
"symfony/property-access": "^4.4|^5.4|^6.0",
"symfony/security-bundle": "^4.4|^5.4|^6.0",
"symfony/security-core": "^4.4|^5.4|^6.0",
"symfony/security-http": "^4.4|^5.4|^6.0"
"symfony/event-dispatcher": "^4.4|^5.3|^6.0",
"symfony/http-foundation": "^4.4|^5.3|^6.0",
"symfony/http-kernel": "^4.4|^5.3|^6.0",
"symfony/property-access": "^4.4|^5.3|^6.0",
"symfony/security-bundle": "^4.4|^5.3|^6.0",
"symfony/security-core": "^4.4|^5.3|^6.0",
"symfony/security-http": "^4.4|^5.3|^6.0"
},
"require-dev": {
"symfony/browser-kit": "^4.4|^5.4|^6.0",
"symfony/console": "^4.4|^5.4|^6.0",
"symfony/dom-crawler": "^4.4|^5.4|^6.0",
"symfony/filesystem": "^4.4|^5.4|^6.0",
"symfony/framework-bundle": "^4.4|^5.4|^6.0",
"symfony/phpunit-bridge": "^4.4|^5.4|^6.0",
"symfony/security-guard": "^4.4|^5.4",
"symfony/var-dumper": "^4.4|^5.4|^6.0",
"symfony/yaml": "^4.4|^5.4|^6.0"
"symfony/browser-kit": "^4.4|^5.3|^6.0",
"symfony/console": "^4.4|^5.3|^6.0",
"symfony/dom-crawler": "^4.4|^5.3|^6.0",
"symfony/filesystem": "^4.4|^5.3|^6.0",
"symfony/framework-bundle": "^4.4|^5.3|^6.0",
"symfony/phpunit-bridge": "^4.4|^5.3|^6.0",
"symfony/security-guard": "^4.4|^5.3",
"symfony/var-dumper": "^4.4|^5.3|^6.0",
"symfony/yaml": "^4.4|^5.3|^6.0"
},
"conflict": {
"symfony/console": "<4.4"
Expand Down

0 comments on commit 82a0e67

Please sign in to comment.