Skip to content

Commit a9726fa

Browse files
Toflarleofeyer
authored andcommitted
Support security encoder and argon2 & co. (see #536)
Description ----------- In Symfony 4.3, a new security encoder named `auto` was introduced. It will choose the best password hashing algorithm based on what Symfony and/or the PHP community decides. Currently this would mean as of PHP 7.2 if you did compile your PHP using libsodium, you'll have argon2 available. I wanted to make sure my setup benefits from the strongest algorithms available so I've implemented the `auto` configuration by default and it will fall back to the current `bcrypt` configuration in case you are not yet on Symfony 4.3. Of course `auto` may still take `bcrypt` in case your system does not support libsodium. While implementing I noticed that we still use the password hashing API directly instead of relying on the Symfony components. This means you can configure a different algorithm in the security configuration but it will never work 😄 So I fixed this by replacing all our direct password hashing API calls with the underlying Symfony security components. BTW: I had to remove the usage of `password_needs_rehash()` to completely rely on the Symfony encoder configured. This means right now you cannot automatically upgrade which is why currently the `SodiumPasswordEncoder` will also verify bcrypt passwords. Symfony will address this in 4.4 so we can (symfony/symfony#31843) completely rely on what Symfony is doing very soon. As of now, there are only `bcrypt` and `argon2` anyway and those will be handled properly. Commits ------- c2c97083 Make sure the password widgets use the configured security encoder and support argon2 and others 12883f1b Replaced direct usage of password_* methods f7872ee9 Fixed class usage 55aa55d9 Fixed UserPasswordCommand tests 62b6531e Fix the coding style
1 parent 0a24e63 commit a9726fa

File tree

16 files changed

+116
-82
lines changed

16 files changed

+116
-82
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ Install Contao and all its dependencies by executing the following command:
3636

3737
```
3838
composer require \
39-
contao/core-bundle:4.7.* \
40-
contao/installation-bundle:^4.7 \
39+
contao/core-bundle:4.8.* \
40+
contao/installation-bundle:^4.8 \
4141
php-http/guzzle6-adapter:^1.1
4242
```
4343

@@ -80,7 +80,7 @@ security:
8080
8181
encoders:
8282
Contao\User:
83-
algorithm: bcrypt
83+
algorithm: auto
8484
8585
firewalls:
8686
dev:

src/Command/UserPasswordCommand.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
namespace Contao\CoreBundle\Command;
1414

15+
use Contao\BackendUser;
1516
use Contao\Config;
1617
use Contao\CoreBundle\Framework\ContaoFramework;
1718
use Doctrine\DBAL\Connection;
@@ -26,6 +27,7 @@
2627
use Symfony\Component\Console\Output\OutputInterface;
2728
use Symfony\Component\Console\Question\Question;
2829
use Symfony\Component\Console\Style\SymfonyStyle;
30+
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
2931

3032
/**
3133
* Changes the password of a Contao back end user.
@@ -42,10 +44,16 @@ class UserPasswordCommand extends Command
4244
*/
4345
private $connection;
4446

45-
public function __construct(ContaoFramework $framework, Connection $connection)
47+
/**
48+
* @var EncoderFactoryInterface
49+
*/
50+
private $encoderFactory;
51+
52+
public function __construct(ContaoFramework $framework, Connection $connection, EncoderFactoryInterface $encoderFactory)
4653
{
4754
$this->framework = $framework;
4855
$this->connection = $connection;
56+
$this->encoderFactory = $encoderFactory;
4957

5058
parent::__construct();
5159
}
@@ -150,6 +158,8 @@ private function validateAndHashPassword(string $password): string
150158
);
151159
}
152160

153-
return password_hash($password, PASSWORD_DEFAULT);
161+
$encoder = $this->encoderFactory->getEncoder(BackendUser::class);
162+
163+
return $encoder->encodePassword($password, null);
154164
}
155165
}

src/DependencyInjection/Compiler/MakeServicesPublicPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function process(ContainerBuilder $container): void
4747
static $aliases = [
4848
'database_connection',
4949
'swiftmailer.mailer',
50+
'security.encoder_factory',
5051
];
5152

5253
foreach ($aliases as $alias) {

src/Resources/config/commands.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ services:
5252
arguments:
5353
- '@contao.framework'
5454
- '@database_connection'
55+
- '@security.encoder_factory'
5556

5657
contao.command.version:
5758
class: Contao\CoreBundle\Command\VersionCommand

src/Resources/contao/config/default.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
// Encryption
5454
$GLOBALS['TL_CONFIG']['encryptionMode'] = 'cfb';
5555
$GLOBALS['TL_CONFIG']['encryptionCipher'] = 'rijndael-256';
56-
$GLOBALS['TL_CONFIG']['bcryptCost'] = 10;
5756

5857
// File uploads
5958
$GLOBALS['TL_CONFIG']['uploadTypes']

src/Resources/contao/controllers/BackendPassword.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ public function run()
8181
// Save the data
8282
else
8383
{
84+
$encoder = System::getContainer()->get('security.encoder_factory')->getEncoder(BackendUser::class);
85+
8486
// Make sure the password has been changed
85-
if (password_verify($pw, $this->User->password))
87+
if ($encoder->isPasswordValid($this->User->password, $pw, null))
8688
{
8789
Message::addError($GLOBALS['TL_LANG']['MSC']['pw_change']);
8890
}
@@ -112,7 +114,7 @@ public function run()
112114

113115
$objUser = UserModel::findByPk($this->User->id);
114116
$objUser->pwChange = '';
115-
$objUser->password = password_hash($pw, PASSWORD_DEFAULT);
117+
$objUser->password = $encoder->encodePassword($pw, null);
116118
$objUser->save();
117119

118120
Message::addConfirmation($GLOBALS['TL_LANG']['MSC']['pw_changed']);

src/Resources/contao/forms/FormPassword.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ protected function validator($varInput)
138138
if (!$this->hasErrors())
139139
{
140140
$this->blnSubmitInput = true;
141+
$encoder = System::getContainer()->get('security.encoder_factory')->getEncoder(FrontendUser::class);
141142

142-
return password_hash($varInput, PASSWORD_DEFAULT);
143+
return $encoder->encodePassword($varInput, null);
143144
}
144145

145146
return '';

src/Resources/contao/library/Contao/Encryption.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ protected static function initialize()
168168
*/
169169
public static function hash($strPassword)
170170
{
171-
return password_hash($strPassword, PASSWORD_DEFAULT);
171+
$encoder = System::getContainer()->get('security.encoder_factory')->getEncoder(User::class);
172+
173+
return $encoder->encodePassword($strPassword, null);
172174
}
173175

174176
/**
@@ -212,7 +214,9 @@ public static function test($strHash)
212214
*/
213215
public static function verify($strPassword, $strHash)
214216
{
215-
return password_verify($strPassword, $strHash);
217+
$encoder = System::getContainer()->get('security.encoder_factory')->getEncoder(User::class);
218+
219+
return $encoder->isPasswordValid($strHash, $strPassword, null);
216220
}
217221

218222
/**

src/Resources/contao/library/Contao/User.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -495,20 +495,6 @@ public static function loadUserByUsername($username)
495495
}
496496
}
497497

498-
// Check if a passwords needs rehashing (see contao/core#8820)
499-
if ($isLogin)
500-
{
501-
$blnAuthenticated = password_verify($request->request->get('password'), $user->password);
502-
$blnNeedsRehash = password_needs_rehash($user->password, PASSWORD_DEFAULT);
503-
504-
// Re-hash the password if the algorithm has changed
505-
if ($blnAuthenticated && $blnNeedsRehash)
506-
{
507-
$user->password = password_hash($request->request->get('password'), PASSWORD_DEFAULT);
508-
$user->save();
509-
}
510-
}
511-
512498
$user->setUserFromDb();
513499

514500
return $user;

src/Resources/contao/modules/ModuleChangePassword.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,16 @@ protected function compile()
143143
$objWidget->validate();
144144

145145
// Validate the old password
146-
if ($strKey == 'oldPassword' && !password_verify($objWidget->value, $objMember->password))
146+
if ($strKey == 'oldPassword')
147147
{
148-
$objWidget->value = '';
149-
$objWidget->addError($GLOBALS['TL_LANG']['MSC']['oldPasswordWrong']);
150-
sleep(2); // Wait 2 seconds while brute forcing :)
148+
$encoder = System::getContainer()->get('security.encoder_factory')->getEncoder(FrontendUser::class);
149+
150+
if (!$encoder->isPasswordValid($objMember->password, $objWidget->value, null))
151+
{
152+
$objWidget->value = '';
153+
$objWidget->addError($GLOBALS['TL_LANG']['MSC']['oldPasswordWrong']);
154+
sleep(2); // Wait 2 seconds while brute forcing :)
155+
}
151156
}
152157

153158
if ($objWidget->hasErrors())

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy