1
votes

because of some special needs I want to use a Guard Authenticator in my Symfony App as described in the Symfony docs (https://symfony.com/doc/current/security/form_login_setup.html). The Authenticator works as I can see from various variable dumps in the Authenticator. But after the redirect the authentication token seams to be lost and I'm redirected to login form again.

Authenticator (simplifed version to debug problem):

<?php 

namespace App\Security;

// use statements omitted

class LoginFormAuthenticatorSimple extends AbstractFormLoginAuthenticator 
{
    use TargetPathTrait;

    private $router;
    private $csrfTokenManager;


    public function __construct(RouterInterface $router,
                                CsrfTokenManagerInterface $csrfTokenManager) 
    {
        $this->router = $router;
        $this->csrfTokenManager = $csrfTokenManager;

    }

    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) {

        $user = new User();
        $user->setUid("jensp");

        $roles = ['ROLE_USER'];
        $user->setRoles($roles);

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        $username = $credentials["username"];
        $password = $credentials["password"];

        if ('' === (string) $password) {
            throw new BadCredentialsException('The presented password must not be empty.');
        }

        return $username === "jensp"  && $password === "test123";
    }

    public function createAuthenticatedToken(UserInterface $user, $providerKey) 
    {
        // Added to check if the token is created...
        dump($user);
        dump($providerKey);
        $token = parent::createAuthenticatedToken($user, $providerKey);

        dump($token);

        return $token;
    }

    public function onAuthenticationSuccess(Request $request, 
                                            TokenInterface $token, 
                                            $providerKey)
    {

        dump($token);
        dump($request);

        if ($targetPath = $this->getTargetPath($request->getSession(), 
                                               $providerKey)) {
            dump($targetPath);                                                   
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->router->generate('show_users'));
    }

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

security.yaml:

firewalls:
    main:
        pattern: ^/(users|groups|selfservice|login_check|form_login_ldap|login)
            anonymous: ~
            logout: ~

            guard:
                authenticators: 
                    - App\Security\LoginFormAuthenticatorSimple    
    access_control:
        - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/users, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/groups, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/self-service, roles: IS_AUTHENTICATED_FULLY }    

Any hints way the user does not stay authenticated?

1
Are you using serialize and unserialize methods in your User Entity? - Alexandre Tranchant
No, the User class has no serialize and unserialize methods. - jensp

1 Answers

2
votes

The problem is your getUser method. You are creating a new User object there, instead of returning the one that's already in your database (or wherever you store your user information).

Try something along the lines of:

public function getUser($credentials, UserProviderInterface $userProvider): UserInterface
{
    try {
        $userProvider->loadUserByUsername($credentials['username']);
    } catch (UsernameNotFoundException $e) {
        throw new AuthenticationException('Username or password is wrong.');
    }
}

This way you are using the injected $userProvider to fetch your already authenticated user.

Side note: You don't need to store any user data in the session. You can use the TokenStorageInterface in your Controllers and Services to get the currently authenticated user.