Warm tip: This article is reproduced from serverfault.com, please click

Using LexikJWTAuthenticationBundle with an LDAP Provider

发布于 2020-01-30 15:26:20

I have a project that use Symfony API-Platform. I want to use LexikJWTAuthenticationBundle on my project but my users are stored in an Active Directory so I set an LDAP UserProvider. I tried to combine the setting of the two following documentation without success :

Here is what I have done

In security.yml :

security:
    providers:
        my_ldap:
            ldap:
                service:     Symfony\Component\Ldap\Ldap
                base_dn:     OU=organization_unit,DC=domain,DC=local
                search_dn:   "OU=organization_unit,DC=domain,DC=local"
                search_password: '%env(resolve:LDAP_PASSWORD)%'
                default_roles: ROLE_USER
                uid_key: uid
firewalls:
    login:
        pattern:  ^/api/login
        stateless: true
        anonymous: true
        json_login:
            provider: my_ldap
            check_path:               /api/login_check
            success_handler:          lexik_jwt_authentication.handler.authentication_success
            failure_handler:          lexik_jwt_authentication.handler.authentication_failure

    api: 
        pattern:   ^/api/
        stateless: true
        guard:
            provider: my_ldap
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

In services.yml :

Symfony\Component\Ldap\Ldap:
    arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
    arguments:
        -   host: '%env(resolve:LDAP_HOST)%'
            port: 636
            # encryption: tls
            options:
                protocol_version: 3
                referrals: false

But when I try to send the request to my_domain/api/login_check with following content :

{
  "username": "my_user",
  "password": "my_password"
}

I received this error as response:

{"code":401,"message":"Invalid credentials."}
Questioner
Pangebo
Viewed
0
Pangebo 2020-03-10 15:58:23

I have resolved my issue by using a custom action that checks if the user exist using LDAP and get its roles. Then, if the freshly retrieved user is authorized to use the application, I create a new token and return it in the response. And finally the token is used to authentify the user for each call he do to the API.

Here is my security.yml

providers:
    # provider to retrieve user from LDAP
    my_ldap:
        id: App\Security\LdapService
    # provider to retrieve user from user
    jwt:
        lexik_jwt:
            class: App\Security\User
firewalls:
    login:
        pattern:  ^/api/login
        stateless: true
        anonymous: true
api: 
        pattern:   ^/api/
        stateless: true
        guard:
            provider: jwt
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

The login action in controller :

/**
 * @Route("/api/login", name="api_login", methods={"POST"})
 */
public function loginCheck(Request $request, LdapService $ldapService, AuthenticationSuccessHandler $authenticationSuccessHandler, AuthenticationFailureHandler $authenticationFailureHandler){
    $content = json_decode($request->getContent());
    $response= new JsonResponse();
    try{
        $user=$ldapService->authenticate($content->username, $content->password);
        return $authenticationSuccessHandler->handleAuthenticationSuccess($user);
    }catch(AuthenticationException $e){
        return $authenticationFailureHandler->onAuthenticationFailure($request, $e);
    }        
    return $response;    
}