Search code examples
ldapsymfony4roles

LDAP role in Symfony 4


I'm using the ldap component on my project in Symfony 4. It works great, authenticates successfully but the only role that I can set on users is the default_role provided in the option of the ldap provider in the security.yaml... All the doc I found wasn't very helpfull whether people use database to manage users or they don't talk about role when they're using the ldap component. Here is my security.yaml if needed :

security.yaml :

security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
    #in_memory: { memory: null }

    my_ldap:
        ldap:
            service: Symfony\Component\Ldap\Ldap
            base_dn: 'my_base_dn'
            search_dn: 'my_search_dn'
            search_password: '%env(resolve:LDAP_PASSWORD)%'
            default_roles: ROLE_USER #rôle par défaut donné à l'utilisateur authentifié

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

        form_login_ldap:
            provider: my_ldap
            service: Symfony\Component\Ldap\Ldap
            dn_string: 'my_dn_string'
            query_string: '(&(sAMAccountName={username})(memberOf=CN=***))'
            login_path: login #route vers laquelle l'utilisateur sera redirigé si il tente d'accéder à une ressource protégé sans être authentifié
        #/!\/!\/!\ NE PAS METTRE EN COMMENTAIRE SINON SUPPRESSION DES LOGS D'ERREURS !! /!\/!\/!\
            check_path: login #route vers laquelle doit être envoyé la requête POST du formulaire
            always_use_default_target_path: true
            default_target_path: homePage #page vers laquelle l'utilisateur authentifié est redirigé

        logout:
                path: app_logout
                target: login
        # activate different ways to authenticate
        # https://symfony.com/doc/current/security.html#firewalls-authentication

        # https://symfony.com/doc/current/security/impersonating_user.html
        # switch_user: true

If anyone have a solution or an idea !!


Solution

  • I am looking for the same feature, but it appears that this hasn't been implemented yet.

    However, there is a feature request for this on GitHub.

    IF your LDAP saves the group membership as an attribute of the user, one workaround would be to check the user object for this attribute in the controller and possibly deny access. You can create a separate method for this, and make sure to call it in every action method that needs security check, like so:

    <?php
    namespace App\Controller;
    
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    
    class SampleController extends AbstractController
    {
        public function index()
        {
            $ldapGroup = 'LDAP-User-Group';
            $this->denyAccessUnlessLdapGroup($ldapGroup, 'ROLE_USER');
            // continue if authenticated
        }
    
        /**
         * Throws an exception unless the current user is member of the specified ldap group
         *
         * @throws AccessDeniedException
         *
         */    
        private function denyAccessUnlessLdapGroup($ldapGroup, $attributes, string $message = 'Access Denied.') {
            $ldapAttribute = 'memberof';
            // usually you'll want to make sure the user is authenticated first
            $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
    
            // returns your User object, or null if the user is not authenticated
            // use inline documentation to tell your editor your exact User class
            // in this case: \Symfony\Component\Ldap\Security\LdapUser
            /** @var \App\Entity\User $user */
            $user = $this->getUser();
            /** @var \Synfony\Component\Ldap\Entry $entry */
            $entry = $user->getEntry();
            if(!$entry->getAttribute($ldapAttribute) ||
             !in_array($ldapGroup, $entry->getAttribute($ldapAttribute))) {
                $exception = $this->createAccessDeniedException($message);
                $exception->setAttributes($attributes);
    
                throw $exception;    
            }
        }
    }
    

    Make sure to customize $ldapGroup and ldapAttribute. The value passed to $attributes is meaningless at this point; I have kept it for consistency for the other denyAccess* methods.