Skip to content

Commit 324f6f6

Browse files
jrushlowweaverryan
authored andcommitted
[make:auth] drop guard support and legacy code cleanup
1 parent e1b781d commit 324f6f6

File tree

51 files changed

+214
-784
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+214
-784
lines changed

src/Generator.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Bundle\MakerBundle;
1313

1414
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15-
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
1615
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
1716
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
1817
use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
@@ -229,7 +228,6 @@ public function generateController(string $controllerClassName, string $controll
229228
$parameters +
230229
[
231230
'generator' => $this->templateComponentGenerator,
232-
'parent_class_name' => static::getControllerBaseClass()->getShortName(),
233231
]
234232
);
235233
}
@@ -246,8 +244,13 @@ public function generateTemplate(string $targetPath, string $templateName, array
246244
);
247245
}
248246

247+
/**
248+
* @deprecated MakerBundle only supports AbstractController::class. This method will be removed in the future.
249+
*/
249250
public static function getControllerBaseClass(): ClassNameDetails
250251
{
252+
trigger_deprecation('symfony/maker-bundle', 'v1.41.0', 'MakerBundle only supports AbstractController. This method will be removed in the future.');
253+
251254
return new ClassNameDetails(AbstractController::class, '\\');
252255
}
253256
}

src/Maker/MakeAuthenticator.php

Lines changed: 64 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\MakerBundle\Maker;
1313

14+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1415
use Symfony\Bundle\MakerBundle\ConsoleStyle;
1516
use Symfony\Bundle\MakerBundle\DependencyBuilder;
1617
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
@@ -23,6 +24,7 @@
2324
use Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder;
2425
use Symfony\Bundle\MakerBundle\Str;
2526
use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator;
27+
use Symfony\Bundle\MakerBundle\Util\TemplateComponentGenerator;
2628
use Symfony\Bundle\MakerBundle\Util\YamlManipulationFailedException;
2729
use Symfony\Bundle\MakerBundle\Util\YamlSourceManipulator;
2830
use Symfony\Bundle\MakerBundle\Validator;
@@ -33,12 +35,22 @@
3335
use Symfony\Component\Console\Input\InputInterface;
3436
use Symfony\Component\Console\Input\InputOption;
3537
use Symfony\Component\Console\Question\Question;
36-
use Symfony\Component\Form\Form;
37-
use Symfony\Component\HttpKernel\Kernel;
38-
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
39-
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
38+
use Symfony\Component\HttpFoundation\RedirectResponse;
39+
use Symfony\Component\HttpFoundation\Request;
40+
use Symfony\Component\HttpFoundation\Response;
41+
use Symfony\Component\Routing\Annotation\Route;
42+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
43+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
44+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
45+
use Symfony\Component\Security\Core\Security;
46+
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
47+
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
48+
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
49+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
4050
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
41-
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
51+
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
52+
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
53+
use Symfony\Component\Security\Http\Util\TargetPathTrait;
4254
use Symfony\Component\Yaml\Yaml;
4355

4456
/**
@@ -53,17 +65,11 @@ final class MakeAuthenticator extends AbstractMaker
5365
private const AUTH_TYPE_FORM_LOGIN = 'form-login';
5466

5567
private $fileManager;
56-
5768
private $configUpdater;
58-
5969
private $generator;
60-
6170
private $doctrineHelper;
62-
6371
private $securityControllerBuilder;
6472

65-
private $useSecurity52 = false;
66-
6773
public function __construct(FileManager $fileManager, SecurityConfigUpdater $configUpdater, Generator $generator, DoctrineHelper $doctrineHelper, SecurityControllerBuilder $securityControllerBuilder)
6874
{
6975
$this->fileManager = $fileManager;
@@ -83,27 +89,22 @@ public static function getCommandDescription(): string
8389
return 'Creates a Guard authenticator of different flavors';
8490
}
8591

86-
public function configureCommand(Command $command, InputConfiguration $inputConfig)
92+
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
8793
{
8894
$command
8995
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeAuth.txt'));
9096
}
9197

92-
public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
98+
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
9399
{
94100
if (!$this->fileManager->fileExists($path = 'config/packages/security.yaml')) {
95101
throw new RuntimeCommandException('The file "config/packages/security.yaml" does not exist. This command requires that file to exist so that it can be updated.');
96102
}
97103
$manipulator = new YamlSourceManipulator($this->fileManager->getFileContents($path));
98104
$securityData = $manipulator->getData();
99105

100-
// Determine if we should use new security features introduced in Symfony 5.2
101-
if ($securityData['security']['enable_authenticator_manager'] ?? false) {
102-
$this->useSecurity52 = true;
103-
}
104-
105-
if ($this->useSecurity52 && !class_exists(UserBadge::class)) {
106-
throw new RuntimeCommandException('MakerBundle does not support generating authenticators using the new authenticator system before symfony/security-bundle 5.2. Please upgrade to 5.2 and try again.');
106+
if (!($securityData['security']['enable_authenticator_manager'] ?? false)) {
107+
throw new RuntimeCommandException('MakerBundle only supports the new authenticator based security system. See https://symfony.com/doc/current/security.html');
107108
}
108109

109110
// authenticator type
@@ -124,14 +125,8 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma
124125

125126
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')) {
126127
$neededDependencies = [TwigBundle::class => 'twig'];
127-
$missingPackagesMessage = 'Twig must be installed to display the login form.';
128-
129-
if (Kernel::VERSION_ID < 40100) {
130-
$neededDependencies[Form::class] = 'symfony/form';
131-
$missingPackagesMessage = 'Twig and symfony/form must be installed to display the login form';
132-
}
128+
$missingPackagesMessage = $this->addDependencies($neededDependencies, 'Twig must be installed to display the login form.');
133129

134-
$missingPackagesMessage = $this->addDependencies($neededDependencies, $missingPackagesMessage);
135130
if ($missingPackagesMessage) {
136131
throw new RuntimeCommandException($missingPackagesMessage);
137132
}
@@ -161,13 +156,6 @@ function ($answer) {
161156

162157
$command->addOption('entry-point', null, InputOption::VALUE_OPTIONAL);
163158

164-
if (!$this->useSecurity52) {
165-
$input->setOption(
166-
'entry-point',
167-
$interactiveSecurityHelper->guessEntryPoint($io, $securityData, $input->getArgument('authenticator-class'), $firewallName)
168-
);
169-
}
170-
171159
if (self::AUTH_TYPE_FORM_LOGIN === $input->getArgument('authenticator-type')) {
172160
$command->addArgument('controller-class', InputArgument::REQUIRED);
173161
$input->setArgument(
@@ -202,7 +190,7 @@ function ($answer) {
202190
}
203191
}
204192

205-
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
193+
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
206194
{
207195
$manipulator = new YamlSourceManipulator($this->fileManager->getFileContents('config/packages/security.yaml'));
208196
$securityData = $manipulator->getData();
@@ -220,7 +208,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
220208

221209
$entryPoint = $input->getOption('entry-point');
222210

223-
if ($this->useSecurity52 && self::AUTH_TYPE_FORM_LOGIN !== $input->getArgument('authenticator-type')) {
211+
if (self::AUTH_TYPE_FORM_LOGIN !== $input->getArgument('authenticator-type')) {
224212
$entryPoint = false;
225213
}
226214

@@ -230,8 +218,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
230218
$input->getOption('firewall-name'),
231219
$entryPoint,
232220
$input->getArgument('authenticator-class'),
233-
$input->hasArgument('logout-setup') ? $input->getArgument('logout-setup') : false,
234-
$this->useSecurity52
221+
$input->hasArgument('logout-setup') ? $input->getArgument('logout-setup') : false
235222
);
236223
$generator->dumpFile($path, $newYaml);
237224
$securityYamlUpdated = true;
@@ -262,45 +249,64 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
262249
);
263250
}
264251

265-
private function generateAuthenticatorClass(array $securityData, string $authenticatorType, string $authenticatorClass, $userClass, $userNameField)
252+
private function generateAuthenticatorClass(array $securityData, string $authenticatorType, string $authenticatorClass, $userClass, $userNameField): void
266253
{
254+
$useStatements = [
255+
Request::class,
256+
Response::class,
257+
TokenInterface::class,
258+
Passport::class,
259+
];
260+
267261
// generate authenticator class
268262
if (self::AUTH_TYPE_EMPTY_AUTHENTICATOR === $authenticatorType) {
263+
$emptyAuthUseStatements = array_merge($useStatements, [
264+
AuthenticationException::class,
265+
AbstractAuthenticator::class,
266+
]);
267+
269268
$this->generator->generateClass(
270269
$authenticatorClass,
271-
sprintf('authenticator/%sEmptyAuthenticator.tpl.php', $this->useSecurity52 ? 'Security52' : ''),
272-
[
273-
'provider_key_type_hint' => $this->getGuardProviderKeyTypeHint(),
274-
'use_legacy_passport_interface' => $this->shouldUseLegacyPassportInterface(),
275-
]
270+
'authenticator/EmptyAuthenticator.tpl.php',
271+
['use_statements' => TemplateComponentGenerator::generateUseStatements($emptyAuthUseStatements)]
276272
);
277273

278274
return;
279275
}
280276

277+
$useStatements = array_merge($useStatements, [
278+
RedirectResponse::class,
279+
UrlGeneratorInterface::class,
280+
Security::class,
281+
AbstractLoginFormAuthenticator::class,
282+
CsrfTokenBadge::class,
283+
UserBadge::class,
284+
PasswordCredentials::class,
285+
TargetPathTrait::class,
286+
]);
287+
281288
$userClassNameDetails = $this->generator->createClassNameDetails(
282289
'\\'.$userClass,
283290
'Entity\\'
284291
);
285292

286293
$this->generator->generateClass(
287294
$authenticatorClass,
288-
sprintf('authenticator/%sLoginFormAuthenticator.tpl.php', $this->useSecurity52 ? 'Security52' : ''),
295+
'authenticator/LoginFormAuthenticator.tpl.php',
289296
[
297+
'use_statements' => TemplateComponentGenerator::generateUseStatements($useStatements),
290298
'user_fully_qualified_class_name' => trim($userClassNameDetails->getFullName(), '\\'),
291299
'user_class_name' => $userClassNameDetails->getShortName(),
292300
'username_field' => $userNameField,
293301
'username_field_label' => Str::asHumanWords($userNameField),
294302
'username_field_var' => Str::asLowerCamelCase($userNameField),
295303
'user_needs_encoder' => $this->userClassHasEncoder($securityData, $userClass),
296304
'user_is_entity' => $this->doctrineHelper->isClassAMappedEntity($userClass),
297-
'provider_key_type_hint' => $this->getGuardProviderKeyTypeHint(),
298-
'use_legacy_passport_interface' => $this->shouldUseLegacyPassportInterface(),
299305
]
300306
);
301307
}
302308

303-
private function generateFormLoginFiles(string $controllerClass, string $userNameField, bool $logoutSetup)
309+
private function generateFormLoginFiles(string $controllerClass, string $userNameField, bool $logoutSetup): void
304310
{
305311
$controllerClassNameDetails = $this->generator->createClassNameDetails(
306312
$controllerClass,
@@ -309,9 +315,16 @@ private function generateFormLoginFiles(string $controllerClass, string $userNam
309315
);
310316

311317
if (!class_exists($controllerClassNameDetails->getFullName())) {
318+
$useStatements = [
319+
AbstractController::class,
320+
Route::class,
321+
AuthenticationUtils::class,
322+
];
323+
312324
$controllerPath = $this->generator->generateController(
313325
$controllerClassNameDetails->getFullName(),
314-
'authenticator/EmptySecurityController.tpl.php'
326+
'authenticator/EmptySecurityController.tpl.php',
327+
['use_statements' => TemplateComponentGenerator::generateUseStatements($useStatements)]
315328
);
316329

317330
$controllerSourceCode = $this->generator->getFileContentsForPendingOperation($controllerPath);
@@ -358,8 +371,7 @@ private function generateNextMessage(bool $securityYamlUpdated, string $authenti
358371
'main',
359372
null,
360373
$authenticatorClass,
361-
$logoutSetup,
362-
$this->useSecurity52
374+
$logoutSetup
363375
);
364376
$nextTexts[] = "- Your <info>security.yaml</info> could not be updated automatically. You'll need to add the following config manually:\n\n".$yamlExample;
365377
}
@@ -371,11 +383,6 @@ private function generateNextMessage(bool $securityYamlUpdated, string $authenti
371383
$nextTexts[] = sprintf('- Review <info>%s::getUser()</info> to make sure it matches your needs.', $authenticatorClass);
372384
}
373385

374-
// this only applies to Guard authentication AND if the user does not have a hasher configured
375-
if (!$this->useSecurity52 && !$this->userClassHasEncoder($securityData, $userClass)) {
376-
$nextTexts[] = sprintf('- Check the user\'s password in <info>%s::checkCredentials()</info>.', $authenticatorClass);
377-
}
378-
379386
$nextTexts[] = '- Review & adapt the login template: <info>'.$this->fileManager->getPathForTemplate('security/login.html.twig').'</info>.';
380387
}
381388

@@ -396,7 +403,7 @@ private function userClassHasEncoder(array $securityData, string $userClass): bo
396403
return $userNeedsEncoder;
397404
}
398405

399-
public function configureDependencies(DependencyBuilder $dependencies, InputInterface $input = null)
406+
public function configureDependencies(DependencyBuilder $dependencies, InputInterface $input = null): void
400407
{
401408
$dependencies->addClassDependency(
402409
SecurityBundle::class,
@@ -409,43 +416,4 @@ public function configureDependencies(DependencyBuilder $dependencies, InputInte
409416
'yaml'
410417
);
411418
}
412-
413-
/**
414-
* Calculates the type-hint used for the $provider argument (string or nothing) for Guard.
415-
*/
416-
private function getGuardProviderKeyTypeHint(): string
417-
{
418-
// doesn't matter: this only applies to non-Guard authenticators
419-
if (!class_exists(AbstractFormLoginAuthenticator::class)) {
420-
return '';
421-
}
422-
423-
$reflectionMethod = new \ReflectionMethod(AbstractFormLoginAuthenticator::class, 'onAuthenticationSuccess');
424-
$type = $reflectionMethod->getParameters()[2]->getType();
425-
426-
if (!$type instanceof \ReflectionNamedType) {
427-
return '';
428-
}
429-
430-
return sprintf('%s ', $type->getName());
431-
}
432-
433-
private function shouldUseLegacyPassportInterface(): bool
434-
{
435-
// only applies to new authenticator security
436-
if (!$this->useSecurity52) {
437-
return false;
438-
}
439-
440-
// legacy: checking for Symfony 5.2 & 5.3 before PassportInterface deprecation
441-
$class = new \ReflectionClass(AuthenticatorInterface::class);
442-
$method = $class->getMethod('authenticate');
443-
444-
// 5.4 where return type is temporarily removed
445-
if (!$method->getReturnType()) {
446-
return false;
447-
}
448-
449-
return PassportInterface::class === $method->getReturnType()->getName();
450-
}
451419
}

0 commit comments

Comments
 (0)