Bonjour à tous,

Développant une application nécessitant une authentification sur un Active Directory, j'ai opté pour le couple FOSUserBundle et IMAGLdapBundle (FR3DLdapBundle n'étant visiblement plus maintenu). J'ai donc suivi la doc pour le paramétrage des bundles et étendu la classe User de FOSUserBundle pour y ajouter des attributs, ce qui me donne la configuration suivante :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
 
# config.yml
fos_user:
    db_driver:      orm
    firewall_name:  main
    user_class:     Acme\UserBundle\Entity\User
 
    group:
        group_class:    Acme\UserBundle\Entity\Group
        group_manager:  sonata.user.orm.group_manager
 
    service:
        user_manager:   sonata.user.orm.user_manager
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
# security.yml
security: 
    ...
 
    encoders:
        Acme\UserBundle\Entity\User: plaintext
 
    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false
 
        main:
            pattern:            ^/
            provider:           ldap
            anonymous:         ~
            imag_ldap:          ~
 
            logout:
                path:           /logout
                target:         /
 
    providers:
        ldap:
            id: imag_ldap.security.user.provider
 
imag_ldap:
    client:
        host: 127.0.0.1
        port: 10389
        referrals_enabled: false
        skip_roles: true
        version: 3
 
    user:
        base_dn: DC=test, DC=fr
        filter: (&(objectClass=person))
        name_attribute: sn
 
    role:
      base_dn: DC=test, DC=fr
      filter: (&(ObjectClass=group))
      name_attribute: sn
      user_attribute: member
 
    user_class: Acme\UserBundle\Entity\User
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
 
#services.yml
services:
    imag_ldap.security.user.provider:
        class: Acme\UserBundle\Security\User\Provider\LdapUserProvider
        arguments:
            - @service_container
            - @imag_ldap.ldap_manager
            - @fos_user.user_manager
            - @validator
            - %imag_ldap.model.user_class%
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
 
<?php
// Acme\UserBundle\Entity\User
namespace Acme\UserBundle\Entity;
 
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as BaseUser;
use IMAG\LdapBundle\User\LdapUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
 
/**
 * @ORM\Entity
 * @ORM\Table(name="person")
 */
class User extends BaseUser implements LdapUserInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
 
    /**
     * @ORM\Column(name="cn", type="string", length=255)
     */
    protected $cn;
 
    /**
     * @ORM\Column(name="dn", type="string", length=255)
     */
    protected $dn;
 
    /**
     * @ORM\Column(name="thumbnail", type="string", length=255)
     */
    protected $thumbnail;
 
    /**
     * @ORM\ManyToOne(targetEntity="Acme\OrgBundle\Entity\Department")
     * @ORM\JoinColumn(name="department_id", referencedColumnName="id")
     */
    protected $department;
 
    /**
     * @ORM\ManyToMany(targetEntity="Acme\UserBundle\Entity\Group")
     * @ORM\JoinTable(name="persons_permissions",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    protected $groups;
 
    protected $attributes;
 
    public function getDn()
    {
        return $this->dn;
    }
 
    public function setDn($dn)
    {
        $this->dn = $dn;
 
        return $this;
    }
 
    public function getCn()
    {
        return $this->cn;
    }
 
    public function setCn($cn)
    {
        $this->cn = $cn;
 
        return $this;
    }
 
    public function getThumbnail()
    {
        return $this->thumbnail;
    }
 
    public function setThumbnail($thumbnail)
    {
        $this->thumbnail = $thumbnail;
 
        return $this;
    }
 
    /**
     * Set department
     *
     * @param \Acme\OrgBundle\Entity\Department $department
     * @return Convention
     */
    public function setDepartment(\Acme\OrgBundle\Entity\Department $department)
    {
        $this->department = $department;
 
        return $this;
    }
 
    /**
     * Get department
     *
     * @return \Acme\OrgBundle\Entity\Department 
     */
    public function getDepartment()
    {
        return $this->department;
    }
 
    public function getAttributes()
    {
        return $this->attributes;
    }
 
    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
 
        return $this;
    }
 
    public function getAttribute($name)
    {
        return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
    }
 
    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof LdapUserInterface
            || $user->getUsername() !== $this->username
            || $user->getEmail() !== $this->email
            || count(array_diff($user->getRoles(), $this->getRoles())) > 0
            || $user->getDn() !== $this->dn
        ) {
            return false;
        }
 
        return true;
    }
 
    public function serialize()
    {
        return serialize(array(
            $this->password,
            $this->salt,
            $this->usernameCanonical,
            $this->username,
            $this->emailCanonical,
            $this->email,
            $this->expired,
            $this->locked,
            $this->credentialsExpired,
            $this->enabled,
            $this->roles,
            $this->id,
            $this->cn,
            $this->dn,
            $this->thumbnail,
        ));
    }
 
    public function unserialize($serialized)
    {
        list(
            $this->password,
            $this->salt,
            $this->usernameCanonical,
            $this->username,
            $this->emailCanonical,
            $this->email,
            $this->expired,
            $this->locked,
            $this->credentialsExpired,
            $this->enabled,
            $this->roles,
            $this->id,
            $this->cn,
            $this->dn,
            $this->thumbnail,
        ) = unserialize($serialized);
    }
}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
 
<?php
// Acme\UserBundle\Security\User\Provider\LdapUserProvider
namespace Acme\UserBundle\Security\User\Provider;
 
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException,
    Symfony\Component\Security\Core\Exception\UnsupportedUserException,
    Symfony\Component\Security\Core\User\UserProviderInterface,
    Symfony\Component\DependencyInjection\ContainerInterface,
    Symfony\Component\Security\Core\User\UserInterface;
 
use IMAG\LdapBundle\Manager\LdapManagerUserInterface,
    IMAG\LdapBundle\User\LdapUserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
 
class LdapUserProvider implements UserProviderInterface
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;
 
    /**
     * @var \IMAG\LdapBundle\Manager\LdapManagerUserInterface
     */
    private $ldapManager;
 
    /**
     * @var \FOS\UserBundle\Model\UserManagerInterface
     */
    protected $userManager;
 
    /**
     * @var \Symfony\Component\Validator\Validator
     */
    protected $validator;
 
    /**
     * Constructor
     *
     * @param ContainerInterface        $container
     * @param LdapManagerUserInterface  $ldapManager
     * @param UserManagerInterface      $userManager
     * @param Validator                 $validator
     */
    public function __construct(ContainerInterface $container, LdapManagerUserInterface $ldapManager, UserManagerInterface $userManager, $validator)
    {
        $this->container = $container;
        $this->ldapManager = $ldapManager;
        $this->userManager = $userManager;
        $this->validator = $validator;
    }
 
    /**
     * {@inheritdoc}
     */
    public function loadUserByUsername($username)
    {
        if (empty($username)) {
            throw new UsernameNotFoundException('The username is not provided.');
        }
 
        $user = $this->userManager->findUserBy(array("username" => $username));
 
        if(empty($user) && !$this->ldapManager->exists($username)) {
            throw new UsernameNotFoundException(sprintf('User "%s" not found', $username));
        }
 
        $lm = $this->ldapManager->setUsername($username)->doPass();
 
        if (empty($user)) {
            $user = $this->userManager->createUser();
            $user
                ->setUsername($lm->getUsername())
                ->setPassword("")
                ->setDn($lm->getDn())
                ->setCn($lm->getCn())
                ->setEmail($lm->getEmail())
                ->setThumbnail($this->getThumbnail($lm->getUsername()));
 
            $this->userManager->updateUser($user);
        }
 
        return $user;
    }
 
    /**
     * {@inheritdoc}
     */
    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof LdapUserInterface) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }
 
        return $this->loadUserByUsername($user->getUsername());
    }
 
    /**
     * {@inheritdoc}
     */
    public function supportsClass($class)
    {
        return $this->userManager->supportsClass($class);
    }
 
   ...
}
Le comportement d'authentification est conforme à mes attentes : lors d'une première connexion, l'utilisateur est bien ajouté en base de données. L'administrateur doit alors lui attribuer un rôle afin qu'il puisse accéder à l'application.

Mon problème tient au fait que les flags de compte ajoutés par FOSUser (enabled, locked, expired) ne sont jamais pris en compte lors de l'authentification, ce qui fait que le seul moyen de bloquer l'accès d'un utilisateur à l'application est de le supprimer complètement. Existe-t-il un moyen de faire fonctionner ces attributs en conjonction avec mon bundle LDAP ?

Merci par avance.