Search code examples
symfonyldapjwtfosuserbundlelexikjwtauthbundle

authentication in symfony api with ldaptools+jwt+fosuser


In my api I'm trying to authenticate a user using LdapToolsBundle, FOSUserBundle and LexikJWTAuthenticationBundle. Doing things step by step and following the integration docs for fosuser and ldaptools and later the jwt docs I manage to acomplish the following:

  1. FosUserBundle + LdapToolsBundle was successfull
  2. Api Integration + FosUserBundle + LdapToolsBundle was successfull
  3. Jwt + FosUserBundle + LdapToolsBundle on Api failed.

the problem is that I just can only log in against my database but not ldap.

in my database I have one user record which I created with fos command and any password(making shure the authentication is on ldap and not fosuser). So far so good. but once instroduced JWT the authentication is made by fosuser instead of ldap authentication guard. When I change the password with fos command I can get the token with out problems.

this is my config:

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: bcrypt
        LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUser: plaintext

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: ROLE_ADMIN

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

        ldap:
            id: ldap_tools.security.user.ldap_user_provider

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        api_login:
            pattern:  ^/login
            stateless: true
            provider: fos_userbundle
            anonymous: true
            form_login:
                check_path:               /login
                require_previous_session: false
                username_parameter:       username
                password_parameter:       password
                success_handler:          lexik_jwt_authentication.handler.authentication_success
                failure_handler:          lexik_jwt_authentication.handler.authentication_failure
                require_previous_session: false
            guard:
                authenticators:
                    - ldap_tools.security.ldap_guard_authenticator
            logout: true

        api:
            pattern:   ^/
            stateless: true
            lexik_jwt: ~

    access_control:
        - { path: ^/login$,           role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/,                 role: IS_AUTHENTICATED_FULLY }

My question is how can I get to work the ldap authenticator? I'll show the wanted workflow

  1. Auth request is received (username and password)
  2. The fosuser provider finds the user or user not found(bad credentials-->end)
  3. The ldap authenticator guard authenticate the user against the domain server or bad credentials -->end
  4. The user is logged in successfully and token is received

but I still getting bad credentials with a registered user in database and domain server (the user credential works)

Thanks in advance!


Solution

  • Here is my answer: Just force the auth after checking the ldap server.

    public function onAuthenticationFailure(AuthenticationFailureEvent $event)//when auth fails on DB(Allways!!!)
        {
            $userToken = $event->getAuthenticationToken();
            $username = $userToken->getUsername();
            $password = $this->requestStack->getCurrentRequest()->get('password');
    
            if ($this->ldapManager->authenticate($username, $password)) {//good credentials
                $token = new UsernamePasswordToken($userToken, 'yes', "public", $userToken->getRoles());
                $this->container->get('security.token_storage')->setToken($token);//set a token
    
                $event = new InteractiveLoginEvent($this->requestStack->getCurrentRequest(), $token); //dispatch the auth event
                $event->stopPropagation();
                $this->container->get('event_dispatcher')->dispatch(SecurityEvents::INTERACTIVE_LOGIN,$event);
    
            }
            //symfony takes care of the response
            }
    

    So far this is the best answer I've found