Skip to content

Commit 7c9ed89

Browse files
committed
WIP - lets pick the correct password encoder to use
1 parent c1c1386 commit 7c9ed89

File tree

9 files changed

+247
-9
lines changed

9 files changed

+247
-9
lines changed

src/Generator.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
1616
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
1717
use Symfony\Bundle\MakerBundle\Util\PhpCompatUtil;
18+
use Symfony\Bundle\MakerBundle\Util\TemplateClassDetails;
19+
use Symfony\Bundle\MakerBundle\Util\TemplateClassFormatter;
1820

1921
/**
2022
* @author Javier Eguiluz <[email protected]>
@@ -26,9 +28,10 @@ class Generator
2628
private $twigHelper;
2729
private $pendingOperations = [];
2830
private $namespacePrefix;
31+
private $templateClassFormatter;
2932
private $phpCompatUtil;
3033

31-
public function __construct(FileManager $fileManager, string $namespacePrefix, PhpCompatUtil $phpCompatUtil = null)
34+
public function __construct(FileManager $fileManager, string $namespacePrefix, PhpCompatUtil $phpCompatUtil = null, TemplateClassFormatter $templateClassFormatter = null)
3235
{
3336
$this->fileManager = $fileManager;
3437
$this->twigHelper = new GeneratorTwigHelper($fileManager);
@@ -41,6 +44,14 @@ public function __construct(FileManager $fileManager, string $namespacePrefix, P
4144
}
4245

4346
$this->phpCompatUtil = $phpCompatUtil;
47+
48+
if (null === $phpCompatUtil) {
49+
$templateClassFormatter = new TemplateClassFormatter($this->phpCompatUtil);
50+
51+
// trigger_deprecation('symfony/maker-bundle', '1.25', 'Initializing Generator without providing an instance of PhpCompatUtil is deprecated.');
52+
}
53+
54+
$this->templateClassFormatter = $templateClassFormatter;
4455
}
4556

4657
/**
@@ -239,4 +250,9 @@ public function generateTemplate(string $targetPath, string $templateName, array
239250
$variables
240251
);
241252
}
253+
254+
public function getTemplateClassDetails(string $fullClassName): TemplateClassDetails
255+
{
256+
return $this->templateClassFormatter->generateClassDetailsForTemplate($fullClassName);
257+
}
242258
}

src/Maker/MakeAuthenticator.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Bundle\MakerBundle\Generator;
2020
use Symfony\Bundle\MakerBundle\InputConfiguration;
2121
use Symfony\Bundle\MakerBundle\Security\InteractiveSecurityHelper;
22+
use Symfony\Bundle\MakerBundle\Security\SecurityCompatUtil;
2223
use Symfony\Bundle\MakerBundle\Security\SecurityConfigUpdater;
2324
use Symfony\Bundle\MakerBundle\Security\SecurityControllerBuilder;
2425
use Symfony\Bundle\MakerBundle\Str;
@@ -60,12 +61,15 @@ final class MakeAuthenticator extends AbstractMaker
6061

6162
private $useSecurity52 = false;
6263

63-
public function __construct(FileManager $fileManager, SecurityConfigUpdater $configUpdater, Generator $generator, DoctrineHelper $doctrineHelper)
64+
private $securityCompatUtil;
65+
66+
public function __construct(FileManager $fileManager, SecurityConfigUpdater $configUpdater, Generator $generator, DoctrineHelper $doctrineHelper, SecurityCompatUtil $securityCompatUtil)
6467
{
6568
$this->fileManager = $fileManager;
6669
$this->configUpdater = $configUpdater;
6770
$this->generator = $generator;
6871
$this->doctrineHelper = $doctrineHelper;
72+
$this->securityCompatUtil = $securityCompatUtil;
6973
}
7074

7175
public static function getCommandName(): string
@@ -275,6 +279,14 @@ private function generateAuthenticatorClass(array $securityData, string $authent
275279
'Entity\\'
276280
);
277281

282+
$hasEncoder = $this->userClassHasEncoder($securityData, $userClass);
283+
$userPasswordEncoder = null;
284+
285+
if ($hasEncoder) {
286+
$encoderDetails = $this->securityCompatUtil->getPasswordEncoderClassNameDetails();
287+
$userPasswordEncoder = $this->generator->getTemplateClassDetails($encoderDetails->getFullName());
288+
}
289+
278290
$this->generator->generateClass(
279291
$authenticatorClass,
280292
sprintf('authenticator/%sLoginFormAuthenticator.tpl.php', $this->useSecurity52 ? 'Security52' : ''),
@@ -285,6 +297,7 @@ private function generateAuthenticatorClass(array $securityData, string $authent
285297
'username_field_label' => Str::asHumanWords($userNameField),
286298
'username_field_var' => Str::asLowerCamelCase($userNameField),
287299
'user_needs_encoder' => $this->userClassHasEncoder($securityData, $userClass),
300+
'password_encoder_details' => $userPasswordEncoder,
288301
'user_is_entity' => $this->doctrineHelper->isClassAMappedEntity($userClass),
289302
'provider_key_type_hint' => $this->providerKeyTypeHint(),
290303
]

src/Resources/config/makers.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<argument type="service" id="maker.security_config_updater" />
1313
<argument type="service" id="maker.generator" />
1414
<argument type="service" id="maker.doctrine_helper" />
15+
<argument type="service" id="maker.security_compat_util" />
1516
<tag name="maker.command" />
1617
</service>
1718

src/Resources/config/services.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
<argument type="service" id="maker.file_manager" />
5151
<argument /> <!-- root namespace -->
5252
<argument type="service" id="maker.php_compat_util" />
53+
<argument type="service" id="maker.template_class_formatter" />
5354
</service>
5455

5556
<service id="maker.entity_class_generator" class="Symfony\Bundle\MakerBundle\Doctrine\EntityClassGenerator">
@@ -68,5 +69,11 @@
6869
<service id="maker.php_compat_util" class="Symfony\Bundle\MakerBundle\Util\PhpCompatUtil">
6970
<argument type="service" id="maker.file_manager" />
7071
</service>
72+
73+
<service id="maker.template_class_formatter" class="Symfony\Bundle\MakerBundle\Util\TemplateClassFormatter">
74+
<argument type="service" id="maker.php_compat_util" />
75+
</service>
76+
77+
<service id="maker.security_compat_util" class="Symfony\Bundle\MakerBundle\Security\SecurityCompatUtil" />
7178
</services>
7279
</container>

src/Resources/skeleton/authenticator/LoginFormAuthenticator.tpl.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Symfony\Component\HttpFoundation\Request;
99
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
1010
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
11-
<?= $user_needs_encoder ? "use Symfony\\Component\\Security\\Core\\Encoder\\UserPasswordEncoderInterface;\n" : null ?>
11+
<?= $user_needs_encoder ? $password_encoder_details->getUseStatement() : null ?>
1212
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
1313
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
1414
use Symfony\Component\Security\Core\Security;
@@ -29,14 +29,14 @@ class <?= $class_name; ?> extends AbstractFormLoginAuthenticator<?= $password_au
2929
<?= $user_is_entity ? " private \$entityManager;\n" : null ?>
3030
private $urlGenerator;
3131
private $csrfTokenManager;
32-
<?= $user_needs_encoder ? " private \$passwordEncoder;\n" : null ?>
32+
<?= $user_needs_encoder ? $password_encoder_details->getPropertyStatement() : null ?>
3333

34-
public function __construct(<?= $user_is_entity ? 'EntityManagerInterface $entityManager, ' : null ?>UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager<?= $user_needs_encoder ? ', UserPasswordEncoderInterface $passwordEncoder' : null ?>)
34+
public function __construct(<?= $user_is_entity ? 'EntityManagerInterface $entityManager, ' : null ?>UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager<?= $user_needs_encoder ? sprintf(', %s', $password_encoder_details->getMethodArgument()) : null ?>)
3535
{
3636
<?= $user_is_entity ? " \$this->entityManager = \$entityManager;\n" : null ?>
3737
$this->urlGenerator = $urlGenerator;
3838
$this->csrfTokenManager = $csrfTokenManager;
39-
<?= $user_needs_encoder ? " \$this->passwordEncoder = \$passwordEncoder;\n" : null ?>
39+
<?= $user_needs_encoder ? $password_encoder_details->getConstructorArgument() : null ?>
4040
}
4141

4242
public function supports(Request $request)
@@ -82,10 +82,13 @@ public function getUser($credentials, UserProviderInterface $userProvider)
8282

8383
public function checkCredentials($credentials, UserInterface $user)
8484
{
85-
<?= $user_needs_encoder ? "return \$this->passwordEncoder->isPasswordValid(\$user, \$credentials['password']);\n"
86-
: "// Check the user's password or other credentials and return true or false
85+
<?php if ($user_needs_encoder): ?>
86+
return <?= $password_encoder_details->getProperty() ?>->isPasswordValid($user, $credentials['password']);
87+
<?php else: ?>
88+
// Check the user's password or other credentials and return true or false
8789
// If there are no credentials to check, you can just return true
88-
throw new \Exception('TODO: check the credentials inside '.__FILE__);\n" ?>
90+
throw new \Exception('TODO: check the credentials inside '.__FILE__);
91+
<?php endif; ?>
8992
}
9093

9194
<?php if ($password_authenticated): ?>

src/Security/SecurityCompatUtil.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\MakerBundle\Security;
13+
14+
use Symfony\Bundle\MakerBundle\Str;
15+
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
16+
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
17+
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
18+
19+
/**
20+
* @author Jesse Rushlow <[email protected]>
21+
*
22+
* @internal
23+
*/
24+
final class SecurityCompatUtil
25+
{
26+
public function getPasswordEncoderClassNameDetails(): ClassNameDetails
27+
{
28+
if (interface_exists(UserPasswordHasherInterface::class)) {
29+
return new ClassNameDetails(UserPasswordHasherInterface::class, Str::getNamespace(UserPasswordHasherInterface::class));
30+
}
31+
32+
return new ClassNameDetails(UserPasswordEncoderInterface::class, Str::getNamespace(UserPasswordEncoderInterface::class));
33+
}
34+
}

src/Util/TemplateClassDetails.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\MakerBundle\Util;
13+
14+
use Symfony\Bundle\MakerBundle\Str;
15+
16+
/**
17+
* @author Jesse Rushlow <[email protected]>
18+
*
19+
* @internal
20+
*/
21+
final class TemplateClassDetails
22+
{
23+
private $fullClassName;
24+
private $shortClassName;
25+
private $isTyped;
26+
27+
public function __construct(string $fullClassName, bool $isTyped)
28+
{
29+
$this->fullClassName = $fullClassName;
30+
$this->shortClassName = Str::getShortClassName($fullClassName);
31+
$this->isTyped = $isTyped;
32+
}
33+
34+
public function getUseStatement(bool $trailingNewLine = true): string
35+
{
36+
$stmt = sprintf('use %s;', $this->fullClassName);
37+
38+
if ($trailingNewLine) {
39+
$stmt = sprintf("%s\n", $stmt);
40+
}
41+
42+
return $stmt;
43+
}
44+
45+
public function getPropertyStatement(bool $trailingNewLine = true, bool $indent = true): string
46+
{
47+
if ($this->isTyped) {
48+
$stmt = sprintf('private %s %s;', $this->shortClassName, $this->getVariable());
49+
} else {
50+
$stmt = sprintf('private %s;', $this->getVariable());
51+
}
52+
53+
if ($trailingNewLine) {
54+
$stmt = sprintf("%s\n", $stmt);
55+
}
56+
57+
if ($indent) {
58+
$stmt = sprintf(' %s', $stmt);
59+
}
60+
61+
return $stmt;
62+
}
63+
64+
public function getConstructorArgument(bool $trailingNewLine = true, bool $indent = true): string
65+
{
66+
$stmt = sprintf('$this->%s = %s;', Str::asLowerCamelCase($this->shortClassName), $this->getVariable());
67+
68+
if ($trailingNewLine) {
69+
$stmt = sprintf("%s\n", $stmt);
70+
}
71+
72+
if ($indent) {
73+
$stmt = sprintf(' %s', $stmt);
74+
}
75+
76+
return $stmt;
77+
}
78+
79+
public function getMethodArgument(): string
80+
{
81+
return sprintf('%s %s', $this->shortClassName, $this->getVariable());
82+
}
83+
84+
public function getProperty(): string
85+
{
86+
return sprintf('$this->%s', Str::asLowerCamelCase($this->shortClassName));
87+
}
88+
89+
public function getVariable(): string
90+
{
91+
return sprintf('$%s', Str::asLowerCamelCase($this->shortClassName));
92+
}
93+
}

src/Util/TemplateClassFormatter.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\MakerBundle\Util;
13+
14+
/**
15+
* @author Jesse Rushlow <[email protected]>
16+
*
17+
* @internal
18+
*/
19+
class TemplateClassFormatter
20+
{
21+
private $phpCompatUtil;
22+
23+
public function __construct(PhpCompatUtil $phpCompatUtil)
24+
{
25+
$this->phpCompatUtil = $phpCompatUtil;
26+
}
27+
28+
public function generateClassDetailsForTemplate(string $className): TemplateClassDetails
29+
{
30+
return new TemplateClassDetails($className, $this->phpCompatUtil->canUseTypedProperties());
31+
}
32+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony MakerBundle package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\MakerBundle\Tests\Util;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\MakerBundle\MakerBundle;
16+
use Symfony\Bundle\MakerBundle\Util\TemplateClassDetails;
17+
18+
/**
19+
* @author Jesse Rushlow <[email protected]>
20+
*/
21+
class TemplateClassDetailsTest extends TestCase
22+
{
23+
public function testDetails(): void
24+
{
25+
$details = new TemplateClassDetails(MakerBundle::class, false);
26+
27+
self::assertSame('use Symfony\Bundle\MakerBundle\MakerBundle;', $details->getUseStatement());
28+
self::assertSame(' private $makerBundle;', $details->getPropertyStatement());
29+
self::assertSame('MakerBundle $makerBundle', $details->getMethodArgument());
30+
self::assertSame('$makerBundle', $details->getVariable());
31+
}
32+
33+
public function testDetailsTypedProperties(): void
34+
{
35+
$details = new TemplateClassDetails(MakerBundle::class, true);
36+
37+
self::assertSame('private MakerBundle $makerBundle;', $details->getPropertyStatement());
38+
}
39+
}

0 commit comments

Comments
 (0)