phpsymfonysulu

Remember me function for custom user login in Sulu CMS


I created a website with a user login using Sulu CMF. For the user login, I would like to create a "remember me" checkbox. According to Symfony docs, all that need to be done is

Symfony docs link

The first two points are straight forward. For the third point, "add Remember Me Support to the Authenticator" I am a bit lost, as with sulu I am not using a custom authenticator, but Sulu rather provides the authentication mechanism, with Sulu users and roles an all that.

How can I tell the Sulu authenticator to add the RememberMeBadge to the authentication Passport as described in the docs?

Update: When loggin in, the server responds with the REMEMBERME cookie, but with the value "deleted".


Solution

  • Finally I got it working by creating a custom Authenticator. The reason why it did not work in the first place is due to the symfony FormLoginAuthenticator that creates the RememberMeBadge, but does not enable it. See https://github.com/symfony/security-http/blob/7.0/Authenticator/FormLoginAuthenticator.php

    Here you see that the RememberMeBadge is disabled by default: https://github.com/symfony/security-http/blob/7.0/Authenticator/Passport/Badge/RememberMeBadge.php

    That fact that the badge is created but not enabled, does not make sense to me, maybe this is a bug in the Symfony framework.

    However, a custom Authenticator that creates and enables the badge, solved the issue for me.

    <?php
    
    namespace App\Security;
    
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
    use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
    use Symfony\Component\Security\Http\SecurityRequestAttributes;
    use Symfony\Component\Security\Http\Util\TargetPathTrait;
    
    class CustomAuthenticator extends AbstractLoginFormAuthenticator
    {
        use TargetPathTrait;
    
        public const LOGIN_ROUTE = 'app_login';
    
        public function __construct(private UrlGeneratorInterface $urlGenerator)
        {
        }
    
        public function authenticate(Request $request): Passport
        {
            $username = $request->request->get('_username', '');
    
            $request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $username);
    
            return new Passport(
                new UserBadge($username),
                new PasswordCredentials($request->request->get('_password', '')),
                [
                    new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
                    (new RememberMeBadge())->enable(),
                ]
            );
        }
    
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
        {
            if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
                return new RedirectResponse($targetPath);
            }
    
            // redirect to homepage
            return new RedirectResponse('/');
        }
    
        protected function getLoginUrl(Request $request): string
        {
            return $this->urlGenerator->generate(self::LOGIN_ROUTE);
        }
    }
    

    The authenticator was created using the symfony cli command php bin/console make:auth with some minor adjustments.