Reputation: 21
I am upgrading an old application to use Symfony (v4) for the back end and I am stuck trying to get authentication functioning. My database stores hashed passwords and salts for the user, passwords used the crypt
php function. I am also using the lexik JWT bundle in an attempt to return a token to the front end.
I cannot get a response other than "bad credentials" from symfony/lexik.
I think my problem is rooted in the encoders portion, I tried to implement a custom password encoder because crypt uses a modified DES algorithm according to the php docs and simply using the following in my security.yaml does not work.
encoders:
App\Entity\DB_1\User:
algorithm: DES
Here is my complete security.yaml
security.yaml
security:
encoders:
App\Entity\DB_1\User:
id: 'App\Security\MyPasswordEncoder'
providers:
entity_provider:
entity:
class: App\Entity\MetallicBonds\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
register:
pattern: ^/register
stateless: true
anonymous: true
api:
pattern: ^/test
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/test, roles: IS_AUTHENTICATED_FULLY }
and my custom password encoder MyPasswordEncoder.php
namespace App\Security;
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
class MyPasswordEncoder extends BasePasswordEncoder implements
PasswordEncoderInterface
{
private $ignorePasswordCase;
public function __construct($ignorePasswordCase = false)
{
$this->ignorePasswordCase = $ignorePasswordCase;
}
public function encodePassword($raw, $salt)
{
// TODO: Implement encodePassword() method.
return crypt($raw,$salt);
}
public function isPasswordValid($encoded, $raw, $salt)
{
// TODO: Implement isPasswordValid() method.
if ($this->isPasswordTooLong($raw)) {
return false;
}
try {
$pass2 = $this->encodePassword($raw, $salt);
} catch (BadCredentialsException $e) {
return false;
}
if (!$this->ignorePasswordCase) {
return $this->comparePasswords($encoded, $pass2);
}
return $this->comparePasswords(strtolower($encoded), strtolower($pass2));
}
}
I would like to use the currently stored passwords, at least for the moment, so the change from the old system to the new will be smooth for the end users. Has anyone had success using a custom password encoder with Symfony 4?
I should note that when I place an xdebug breakpoint in MyPasswordEncoder.php, it never stops the application, is there somewhere else the class needs to be registered for Symfony to use it?
Upvotes: 1
Views: 4408
Reputation: 71
this is my security.yaml
security:
encoders:
App\Entity\User:
id: 'App\Security\Encoder\MyCustomPasswordEncoder'
this is my code
namespace App\Security\Encoder;
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
class MyCustomPasswordEncoder extends BasePasswordEncoder
{
private $algorithm;
private $encodeHashAsBase64;
private $iterations;
/**
* @param string $algorithm The digest algorithm to use
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
* @param int $iterations The number of iterations to use to stretch the password hash
*/
public function __construct(string $algorithm = 'sha1', bool $encodeHashAsBase64 = false, int $iterations = 0)
{
$this->algorithm = $algorithm;
$this->encodeHashAsBase64 = $encodeHashAsBase64;
$this->iterations = $iterations;
}
/**
* {@inheritdoc}
*/
public function encodePassword($raw, $salt)
{
if ($this->isPasswordTooLong($raw)) {
throw new BadCredentialsException('Invalid password.');
}
if (!in_array($this->algorithm, hash_algos(), true)) {
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
}
//$salted = $this->mergePasswordAndSalt($raw, $salt);
$salted = $salt.$raw;
$digest = hash($this->algorithm, $salted, true);
// "stretch" hash
for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
}
/**
* {@inheritdoc}
*/
public function isPasswordValid($encoded, $raw, $salt)
{
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
}
}
Code is correctly run. old code is symfony 1.4.
Upvotes: 1