1
votes

Working with Symfony 4, and making an User environment (using SymfonyCast tutorials) I wrote a LoginFormAuthenticator :

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

    public function supports(Request $request)
    {
        return 'login' === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function getCredentials(Request $request)
    {
        $credentials = [
            'username' => $request->request->get('username'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['username']
        );

        return $credentials;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('L\'username ne peut pas être trouvé.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->urlGenerator->generate('core_home'));
    }

    protected function getLoginUrl()
    {
        return $this->urlGenerator->generate('login');
    }
}
`

But the issue is in the csrf protection. (after many searches, reducing the area of the issue) : I can't connect with my username, a loop give me always the form, with last username...

From the log :

[2019-11-16 15:27:17] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\Security\LoginFormAuthenticator"} [] [2019-11-16 15:27:17] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"App\Security\LoginFormAuthenticator"} []

Trying to better understand, I put a dd() in the getUser function :

$token = new CsrfToken('authenticate', $credentials['csrf_token']); dd($token);

and the result is :

LoginFormAuthenticator.php on line 63: CsrfToken^ {#345 ▼ -id: "authenticate" -value: "A11CgM6FtyduixvNmOotNkjqbakFCfYPD-TSXv8_PGE" }

We have a Csrf token. Searching more, I put in CsrfTokenManager (from Symfony/Security/Csrf) two dump() an a dd() in the istokenValid function :

    public function isTokenValid(CsrfToken $token)
{
    dump($token);
    $namespacedId = $this->getNamespace().$token->getId();
    dump($namespacedId);
    if (!$this->storage->hasToken($namespacedId)) {
    dd(!$this->storage->hasToken($namespacedId));
     return false;
    }

    return hash_equals($this->storage->getToken($namespacedId), $token->getValue());
}

and the results are :

CsrfTokenManager.php on line 109:

CsrfToken^ {#345 ▼ -id: "authenticate" -value: "YPZIzpw_8eU5Uy3YvV6PwySz4qz8FIz0EzkIwkBd-OQ" }

CsrfTokenManager.php on line 111:

"authenticate"

CsrfTokenManager.php on line 113:

true

So, if I understand well, we have a cookie, and the function return 'this cookie is not valid'...

What's wrong ?

1
Many thanks to @Albeis, who edited my post. I don't know if the issue is exactly the same, but I have observed that, trying to connect to the site (in prod environment) with diverse Ipad and Iphone, I can note exactly the same behavior : the process is interrupted, and return to the beginning of the login. - D.Picard

1 Answers

0
votes

Eventually, we find our issue. With the great help of Ryan Weaver from SymfonyCast. Trying to manage the duration of the session, we have configured the handle_id and the cookie_path in framework.yaml ! And even if msDos and Linux accept it, AppleOs don't accept. That's all... :(