IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

Symfony Guard Authenticator


Sujet :

Symfony PHP

  1. #21
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Oui c'est ça, l'objet que je reçois est un App\Entity\User, il est créé dans la BDD si c'est la première fois qu'il se connecte via LDAP. Et oui, son mot de passe n'est pas stocké en BDD. Dans la classe LdapUserProvider, qui s'occupe de récupérer le User via une connexion LDAP et de le load il y a une méthode getPassword mais j'avoue ne pas trop comprendre ce qu'elle fait, donc je me demandais si je pouvais l'utiliser pour récupérer le mot de passe de l'utilisateur:
    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
    /**
         * Fetches the password from an LDAP entry.
         *
         * @param null|Entry $entry
         */
        private function getPassword(Entry $entry)
        {
            if (null === $this->passwordAttribute) {
                return;
            }
     
            if (!$entry->hasAttribute($this->passwordAttribute)) {
                throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $this->passwordAttribute, $entry->getDn()));
            }
     
            $values = $entry->getAttribute($this->passwordAttribute);
     
            if (1 !== count($values)) {
                throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $this->passwordAttribute));
            }
     
            return $values[0];
        }
    Merci pour tes liens, je vais tester tout ça!

  2. #22
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Je pense avoir trouvé une piste. Mon LdapUser a un attribut password. Et quand je suis dans la boucle de connexion Ldap, le loadUser est appelé, dans mon LdapUserProvider:
    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
    protected function loadUser($username, Entry $entry)
        {
            $userRepository = $this->em->getRepository("App:User");
            //On récupère les infos de l'utilisateur qui se connecte
            $user = $userRepository->findOneBy(array("username" => $username));
     
            //Si l'utilisateur est null, donc pas présent en BDD mais OK niveau LDAP
            if ($user === null) {
                //Créé un User pour l'ajouter à la BDD une fois qu'on s'est assuré que c'était bien un utilisateur LDAP
                //Cas première connexion de l'utilisateur
                $user = new User();
                $user->setFirstname($entry->getAttribute("givenName")[0]);
                $user->setLastname($entry->getAttribute("sn")[0]);
                $user->setEmail($entry->getAttribute("mail")[0]);
                $user->setUsername($entry->getAttribute("uid")[0]);
                $user->setRoles($this->defaultRoles);
     
                $this->em->persist($user);
                $this->em->flush();
            } else {
                $this->em->flush();
            }
     
            return $user;
        }
    C'est ce qui est dans la méthode. En fait, là on enregistre l'utilisateur venant dans Ldap en BDD lors de sa première connexion et on renvoie ce User, qui est au final un simple App\Entity\User, et non un LdapUser! Or, ce serait plus logique de renvoyer un utilisateur Ldap, non? Donc voilà ce que j'ai commencé à faire pour qu'on enregistre bien l'utilisateur en BDD lors de sa première connexion, et sinon on créé un utilisateur Ldap:
    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
    protected function loadUser($username, Entry $entry)
        {
            $userRepository = $this->em->getRepository("App:User");
            //On récupère les infos de l'utilisateur qui se connecte
            $user = $userRepository->findOneBy(array("username" => $username));
     
            //Si l'utilisateur est null, donc pas présent en BDD mais OK niveau LDAP
            if ($user === null) {
                //Créé un User pour l'ajouter à la BDD une fois qu'on s'est assuré que c'était bien un utilisateur LDAP
                //Cas première connexion de l'utilisateur
                $user = new User();
                $user->setFirstname($entry->getAttribute("givenName")[0]);
                $user->setLastname($entry->getAttribute("sn")[0]);
                $user->setEmail($entry->getAttribute("mail")[0]);
                $user->setUsername($entry->getAttribute("uid")[0]);
                $user->setRoles($this->defaultRoles);
     
                $this->em->persist($user);
                $this->em->flush();
            } else {
                $this->em->flush();
                $password = null;
                $extraFields = [];
                if (null !== $this->passwordAttribute) {
                    $password = $this->getAttributeValue($entry, $this->passwordAttribute);
                }
     
                foreach ($this->extraFields as $field) {
                    $extraFields[$field] = $this->getAttributeValue($entry, $field);
                }
                return new LdapUser($entry, $username, $password, $this->defaultRoles, $extraFields);
            }
     
            return null;
        }
    Mais ça fait qu'à chaque connexion un nouveau LdapUser est créé, est-ce que ça peut poser problème? Est-ce une bonne façon de faire?

    Edit 2 :
    Après quelques recherches je vois que le mot de passe serait vérifié dans la fonction checkAuthentication de LdapBindAuthenticationProvider qui se situe dans le vendor. Je voulais exploiter ça mais il semblerait que le code ne rentre pas dans cette classe alors qu'elle devrait être appelée automatiquement, peut-être ça le problème?

    Edit: j'ai regardé les infos contenues dans l'objet Entry, et il n'y a pas le password encore une fois :/ Le seul blocage que j'ai c'est vraiment récupérer le mot de passe et le comparer, et ensuite tout sera OK
    Les options que l'on peut passer à query sont:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Defined options are: "attrsOnly", "deref", "filter", "maxItems", "pageSize", "scope", "sizeLimit", "timeout".
    Par défaut, on dirait qu'aucune n'est utilisée. J'ai regardé pour les extraFields et j'ai découvert le passwordAttribute, qui est à null. Je pense que je dois jouer avec ça pour trouver quel est le passwordAttribute du LDAP et pouvoir le récupérer (j'espère).

  3. #23
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2011
    Messages
    351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2011
    Messages : 351
    Points : 582
    Points
    582
    Par défaut
    Est-ce que tu pourrais faire un résumé de là où tu en es stp ? (repartager le code pertinent dans son état actuel et expliquer sur quel point précis tu bloques)

    J'ai un peu du mal à suivre avec tes différents edits et sans avoir le code sous les yeux (puis quand tu fais références à des fichiers tiers, par exemple dans le dossier vendor, précise si possible quelle est la version du package qui est utilisée composer show <lenom/dupackage> car le composant Security a beaucoup évolué ces derniers temps).

    Merci !

  4. #24
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Oui pardon! Alors, l'authentification via BDD marche niquel. J'ai donc commencé à implémenter l'authentification via Symfony, en prenant des exemples sur Internet. J'ai suivi cette doc. Mon code LoginLdapFormAuthenticator:
    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
    <?php
     
    namespace App\Security;
     
    use App\Entity\User;
    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Ldap\Entry;
    use Symfony\Component\Ldap\Ldap;
    use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
    use Symfony\Component\Security\Core\Exception\AuthenticationException;
    use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
    use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
    use Symfony\Component\Security\Core\Security;
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\User\UserProviderInterface;
    use Symfony\Component\Security\Csrf\CsrfToken;
    use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
    use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
    use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
    use Symfony\Component\Security\Http\Util\TargetPathTrait;
     
    class LoginLdapFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
    {
        use TargetPathTrait;
     
        public const LOGIN_ROUTE = 'app_login';
     
        private $entityManager;
        private $urlGenerator;
        private $csrfTokenManager;
        private $passwordEncoder;
        private $ldap;
        private $ldapUserProvider;
     
        public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder, Ldap $ldap, LdapUserProvider $ldapUserProvider)
        {
            $this->entityManager = $entityManager;
            $this->urlGenerator = $urlGenerator;
            $this->csrfTokenManager = $csrfTokenManager;
            $this->passwordEncoder = $passwordEncoder;
            $this->ldap = $ldap;
            $this->ldapUserProvider = $ldapUserProvider;
        }
     
        public function supports(Request $request)
        {
            dump("supports LDAP");
            //Si on retourne false rien ne se passe
            //Si on retourne true, appel à getCredentials()
            return self::LOGIN_ROUTE === $request->attributes->get('_route')
                && $request->isMethod('POST');
        }
     
        public function getCredentials(Request $request)
        {
            $credentials = [
                'csrf_token' => $request->request->get('_csrf_token'),
                'username' => $request->request->get('_username'),
                'password' => $request->request->get('_password'),
                'submit' => $request->request->get('_submit'),
            ];
            $request->getSession()->set(
                Security::LAST_USERNAME,
                $credentials['username']
            );
     
            return $credentials;
        }
     
        //Doit retourner un User de type UserInterface
        public function getUser($credentials, UserProviderInterface $userProvider)
        {
            dump("getUser LDAP");
            $token = new CsrfToken('authenticate', $credentials['csrf_token']);
            if (!$this->csrfTokenManager->isTokenValid($token)) {
                throw new InvalidCsrfTokenException();
            }
     
            $user = $this->ldapUserProvider->loadUserByUsername($credentials['username']);
     
            if (!$user) {
                // fail authentication with a custom error
                throw new CustomUserMessageAuthenticationException('Username could not be found.');
            }
     
            return $user;
        }
     
        //Vérifier que le mdp est bon
        public function checkCredentials($credentials, UserInterface $user)
        {
            //$pass = $this->ldapUserProvider->getPassword($user->getEntry());
            //dd($pass);
            return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
        }
     
        /**
         * Used to upgrade (rehash) the user's password automatically over time.
         */
        public function getPassword($credentials): ?string
        {
            return $credentials['password'];
        }
     
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
        {
            if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
                return new RedirectResponse($targetPath);
            }
     
            // For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
            return new RedirectResponse($this->urlGenerator->generate('fos_user_profile_show'));
        }
     
     
        public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
        {
            return null;
        }
     
        protected function getLoginUrl()
        {
            return $this->urlGenerator->generate(self::LOGIN_ROUTE);
        }
     
    }
    Tout se passe bien jusque la fonction checkCredentials. En effet, je ne vois pas comment comparer les mots de passes étant donné que je ne reçois pas le mot de passe LDAP. En cherchant un peu, il semblerait que la méthode checkAuthentication dans la classe LdapBindAuthenticationProvider regarde si le mot de passe entré par l'utilisateur correspond à celui du LDAP. Voici le code de LdapBindAuthenticationProvider:
    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
    <?php
     
    /*
     * This file is part of the Symfony package.
     *
     * (c) Fabien Potencier <fabien@symfony.com>
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */
     
    namespace Symfony\Component\Security\Core\Authentication\Provider;
     
    use Symfony\Component\Ldap\Exception\ConnectionException;
    use Symfony\Component\Ldap\LdapInterface;
    use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
    use Symfony\Component\Security\Core\Exception\BadCredentialsException;
    use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
    use Symfony\Component\Security\Core\User\UserCheckerInterface;
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\User\UserProviderInterface;
     
    /**
     * LdapBindAuthenticationProvider authenticates a user against an LDAP server.
     *
     * The only way to check user credentials is to try to connect the user with its
     * credentials to the ldap.
     *
     * @author Charles Sarrazin <charles@sarraz.in>
     */
    class LdapBindAuthenticationProvider extends UserAuthenticationProvider
    {
        private $userProvider;
        private $ldap;
        private $dnString;
        private $queryString;
        private $searchDn;
        private $searchPassword;
     
        public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, LdapInterface $ldap, string $dnString = '{username}', bool $hideUserNotFoundExceptions = true, string $searchDn = '', string $searchPassword = '')
        {
            parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
     
            $this->userProvider = $userProvider;
            $this->ldap = $ldap;
            $this->dnString = $dnString;
            $this->searchDn = $searchDn;
            $this->searchPassword = $searchPassword;
        }
     
        /**
         * Set a query string to use in order to find a DN for the username.
         *
         * @param string $queryString
         */
        public function setQueryString($queryString)
        {
            $this->queryString = $queryString;
        }
     
        /**
         * {@inheritdoc}
         */
        protected function retrieveUser($username, UsernamePasswordToken $token)
        {
            if (AuthenticationProviderInterface::USERNAME_NONE_PROVIDED === $username) {
                throw new UsernameNotFoundException('Username can not be null.');
            }
     
            return $this->userProvider->loadUserByUsername($username);
        }
     
        /**
         * {@inheritdoc}
         */
        protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
        {
            $username = $token->getUsername();
            $password = $token->getCredentials();
     
            if ('' === (string) $password) {
                throw new BadCredentialsException('The presented password must not be empty.');
            }
     
            try {
                if ($this->queryString) {
                    if ('' !== $this->searchDn && '' !== $this->searchPassword) {
                        $this->ldap->bind($this->searchDn, $this->searchPassword);
                    } else {
                        @trigger_error('Using the "query_string" config without using a "search_dn" and a "search_password" is deprecated since Symfony 4.4 and will throw an exception in Symfony 5.0.', E_USER_DEPRECATED);
                    }
                    $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
                    $query = str_replace('{username}', $username, $this->queryString);
                    $result = $this->ldap->query($this->dnString, $query)->execute();
                    if (1 !== $result->count()) {
                        throw new BadCredentialsException('The presented username is invalid.');
                    }
     
                    $dn = $result[0]->getDn();
                } else {
                    $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_DN);
                    $dn = str_replace('{username}', $username, $this->dnString);
                }
                dd($dn,$password);
                $this->ldap->bind($dn, $password);
            } catch (ConnectionException $e) {
                throw new BadCredentialsException('The presented password is invalid.');
            }
        }
    }
    Cette classe est dans le vendor, package:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @TH-UCLX0118-01:~/projets/Intranet$ composer show symfony/security-core
    name     : symfony/security-core
    descrip. : Symfony Security Component - Core Library
    keywords : 
    versions : * v4.4.11
    Je ne vois pas comment forcer l'appel à cette méthode dans mon code pour voir ce qu'elle retourne. Par ailleurs dans le code LdapUserProvider il y a un attribut $passwordAttribute qui est après utilisé pour la modification du mot de passe par exemple. le code LdapUserProvider:
    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
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    <?php
     
     
    namespace App\Security;
     
     
    use Doctrine\ORM\EntityManagerInterface;
    use App\Entity\User;
    use Symfony\Component\Ldap\Entry;
    use Symfony\Component\Ldap\Exception\ConnectionException;
    use Symfony\Component\Ldap\Exception\ExceptionInterface;
    use Symfony\Component\Ldap\LdapInterface;
    use Symfony\Component\Ldap\Ldap;
    use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
    use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
    use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
    use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\User\UserProviderInterface;
     
     
    class LdapUserProvider implements UserProviderInterface, PasswordUpgraderInterface
    {
        private $ldap;
        private $baseDn;
        private $searchDn;
        private $searchPassword;
        private $defaultRoles;
        private $uidKey;
        private $defaultSearch;
        private $passwordAttribute;
        private $extraFields;
        //New
        private $em;
     
        public function __construct(Ldap $ldap, string $baseDn, EntityManagerInterface $em , string $searchDn = null, string $searchPassword = null, array $defaultRoles = [], string $uidKey = null, string $filter = null, string $passwordAttribute = null, array $extraFields = [])
        {
            if (null === $uidKey) {
                $uidKey = 'sAMAccountName';
            }
     
            if (null === $filter) {
                $filter = '({uid_key}={username})';
            }
     
            $this->ldap = $ldap;
            $this->baseDn = $baseDn;
            $this->searchDn = $searchDn;
            $this->searchPassword = $searchPassword;
            $this->defaultRoles = $defaultRoles;
            $this->uidKey = $uidKey;
            $this->defaultSearch = str_replace('{uid_key}', $uidKey, $filter);
            $this->passwordAttribute = $passwordAttribute;
            $this->extraFields = $extraFields;
            $this->em = $em;
        }
     
        /**
         * {@inheritdoc}
         */
        public function loadUserByUsername($username)
        {
            try {
                $this->ldap->bind($this->searchDn, $this->searchPassword);
                $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
                $query = str_replace('{username}', $username, $this->defaultSearch);
                $search = $this->ldap->query($this->baseDn, $query);
            } catch (ConnectionException $e) {
                throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
            }
     
            $entries = $search->execute();
            $count = \count($entries);
     
            if (!$count) {
                throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
            }
     
            if ($count > 1) {
                throw new UsernameNotFoundException('More than one user found.');
            }
     
            return $this->loadUser($username, $entries[0]);
        }
     
        /**
         * {@inheritdoc}
         */
        public function refreshUser(UserInterface $user)
        {
            if (!$user instanceof LdapUser || !$user instanceof User) {
                throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
            }
     
            //New
            $userRepository = $this->em->getRepository("AppBundle:User");
            $user = $userRepository->findOneBy(array("username" => $user->getUsername()));
     
            if($user === null){
                throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
            }
     
            return new LdapUser($user->getEntry(), $user->getUsername(), $user->getPassword(), $user->getRoles(), $user->getExtraFields());
        }
     
        /**
         * {@inheritdoc}
         */
        public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
        {
            if (!$user instanceof LdapUser) {
                throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
            }
     
            if (null === $this->passwordAttribute) {
                return;
            }
     
            try {
                $user->getEntry()->setAttribute($this->passwordAttribute, [$newEncodedPassword]);
                $this->ldap->getEntryManager()->update($user->getEntry());
                $user->setPassword($newEncodedPassword);
            } catch (ExceptionInterface $e) {
                // ignore failed password upgrades
            }
        }
     
        /**
         * {@inheritdoc}
         */
        public function supportsClass($class)
        {
            return LdapUser::class === $class;
        }
     
        /**
         * Loads a user from an LDAP entry.
         *
         * @param $username
         * @param Entry $entry
         * @return UserInterface
         */
        protected function loadUser($username, Entry $entry)
        {
            $userRepository = $this->em->getRepository("App:User");
            //On récupère les infos de l'utilisateur qui se connecte
            $user = $userRepository->findOneBy(array("username" => $username));
     
            //Si l'utilisateur est null, donc pas présent en BDD mais OK niveau LDAP
            if ($user === null) {
                //Créé un User pour l'ajouter à la BDD une fois qu'on s'est assuré que c'était bien un utilisateur LDAP
                //Cas première connexion de l'utilisateur
                $user = new User();
                $user->setFirstname($entry->getAttribute("givenName")[0]);
                $user->setLastname($entry->getAttribute("sn")[0]);
                $user->setEmail($entry->getAttribute("mail")[0]);
                $user->setUsername($entry->getAttribute("uid")[0]);
                $user->setRoles($this->defaultRoles);
     
                $this->em->persist($user);
                $this->em->flush();
            }else{
                $this->em->flush();
            }
     
            return $user;
     
        }
        /**
         * Fetches the password from an LDAP entry.
         *
         * @param null|Entry $entry
         */
        private function getPassword(Entry $entry)
        {
            if (null === $this->passwordAttribute) {
                return;
            }
     
            if (!$entry->hasAttribute($this->passwordAttribute)) {
                throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $this->passwordAttribute, $entry->getDn()));
            }
     
            $values = $entry->getAttribute($this->passwordAttribute);
     
            if (1 !== count($values)) {
                throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $this->passwordAttribute));
            }
     
            return $values[0];
        }
     
        private function getAttributeValue(Entry $entry, string $attribute)
        {
            var_dump("getAttributeValue ".$attribute);
            if (!$entry->hasAttribute($attribute)) {
                throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $attribute, $entry->getDn()));
            }
     
            $values = $entry->getAttribute($attribute);
     
            if (1 !== \count($values)) {
                throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $attribute));
            }
     
            return $values[0];
        }
    }
    Sauf que cet attribut est nul, puisque je ne le définit à aucun moment. Quand j'ai demandé à mes collègues le nom du champ password dans le LDAP pour pouvoir récupérer le password via le LDAP pour le comparer ils ne me l'ont pas donné car cela pourrait apparemment créer des failles de sécurité si on le reçevait et qu'on le comparait. Dans la doc que j'ai citée au début de mon message, ils parlent d'utiliser "l'instruction $this->ldap->bind($dn, $password);. Cette fois le DN contiendra le nom de l'utilisateur à authentifier et $password son mot de passe." J'ai donc essayé dans ma méthode checkCredentials de ma classe LoginLdapFormAuthenticator:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public function checkCredentials($credentials, UserInterface $user)
        {
            $this->ldap->bind($credentials['username'], $credentials['password']);
            return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
        }
    Mais ça me retourne une erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    InvalidCredentialsException
    J'imagine qu'il essaye de se connecter au Ldap et non à l'utilisateur comme noté dans la doc. Les informations de connexion Ldap sont donc mauvaises puisque ce sont celles de mon utilisateur.
    Je suis donc bloquée à ce niveau, je ne vois pas comment continuer. Merci de ton aide

  5. #25
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Je pense avoir réussi! Je ne mettais pas le bon dn pour le ldap->bind. J'ai donc fait un test en récupérant le dn qui étais associé à mon utilisateur et en le mettant directement dans mon ldap->bind comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public function checkCredentials($username, $password){
            $dnSearchUser = "CN=XXX,OU=COMPTES UTILISATEURS,OU=COMPTES,OU=XXX,OU=XX FRANCE,OU=XX-XX,DC=XX-XX,DC=lan";
            $this->ldap->bind($dnSearchUser, $password);
            return true;
        }
    J'ai mis un return true puisque si la connexion ne marche pas cela m'affiche une erreur InvalidCredentials. Et ça semble marcher! Il faut donc que je modifie pour récupérer directement le dn depuis l'objet Entry de l'utilisateur pour que ça s'adapte à tous les utilisateurs.
    J'ai une question par contre: Comment faire pour que l'erreur InvalidCredentials n'affiche pas une page rouge mais retourne la page de login avec un message en rouge plutôt?

  6. #26
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2011
    Messages
    351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2011
    Messages : 351
    Points : 582
    Points
    582
    Par défaut
    Faudrait qu'un jour je me replonge sérieusement dans LDAP, car là je suis un peu perdu avec les DN etc (mais le principal étant que tu ne le sois pas^^).

    Cool si ça prend forme petit à petit !

    Citation Envoyé par Akame14 Voir le message
    J'ai une question par contre: Comment faire pour que l'erreur InvalidCredentials n'affiche pas une page rouge mais retourne la page de login avec un message en rouge plutôt?
    En encapsulant le code en question dans un try/catch et en levant une Exception de type AuthenticationException à l'intérieur du catch ?
    Dans l'AuthenticatorInterface on peut lire ceci dans le docblock de checkCredentials :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Returns true if the credentials are valid. If false is returned, authentication will fail. You may also throw an AuthenticationException if you wish to cause authentication to fail.

  7. #27
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Oui c'est super compliqué!
    Voilà ce que j'ai essayé de faire pour l'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public function checkCredentials($dnSearchUser, $password){
            try{
     
                $this->ldap->bind($dnSearchUser, $password);
            } catch (AuthenticationException $e){
                return false;
            }
            return true;
        }
    Mais toujours pareil, j'ai une page d'erreur. Voici l'erreur un peu plus détaillée:
    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
     
    Symfony\Component\Ldap\Exception\
     InvalidCredentialsException
    in vendor/symfony/ldap/Adapter/ExtLdap/Connection.php (line 64)
    in vendor/symfony/ldap/Ldap.php->bind (line 40)
    Ldap->bind('username', 'pass') in src/Security/LdapUserProvider.php (line 214)
     
            public function checkCredentials($dnSearchUser, $password){
                try{
                    $this->ldap->bind($dnSearchUser, $password);
                } catch (AuthenticationException $e){
                    return false;
                }
                return true;
            }
    Après le bind se fait dans une classe du vendor donc je ne peux pas la modifier. Est-ce bien comme cela qu'il faut faire?

  8. #28
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mai 2017
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2017
    Messages : 87
    Points : 49
    Points
    49
    Par défaut
    Bon j'ai compris, il fallait que je catch l'erreur qui était déclenchée évidement Bon et bien il semblerait que tout marche, connexion LDAP et BDD okay, et message d'erreur quand il y a une exception au lieu d'une page rouge!
    Merci énormément pour ton temps et tes conseils! Bonne continuation

  9. #29
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2011
    Messages
    351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2011
    Messages : 351
    Points : 582
    Points
    582
    Par défaut
    Super !

    Si jamais pour personnaliser le message d'erreur : https://symfony.com/doc/current/secu...error-messages
    Et notamment ce passage là :
    But, you can also return a custom message by throwing a Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException. You can throw this from getCredentials(), getUser() or checkCredentials() to cause a failure
    Bonne continuation à toi aussi.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/03/2020, 13h02
  2. [3.x] Utiliser guard Symfony avec multiple provider
    Par Wilhem31 dans le forum Symfony
    Réponses: 1
    Dernier message: 11/09/2018, 11h43
  3. [Securité] Différence entre Impersonation et Authentication?
    Par Laurent Dardenne dans le forum Windows
    Réponses: 6
    Dernier message: 13/08/2009, 11h32
  4. Body...guard
    Par Sylvain James dans le forum XMLRAD
    Réponses: 4
    Dernier message: 11/03/2005, 15h07
  5. Mise en place d'une solution Data Guard 9i R2
    Par user_oracle dans le forum Oracle
    Réponses: 4
    Dernier message: 16/02/2005, 10h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo