Сохранение объекта пользователя LDAP в базе данных без пароля

Теория: есть ли способ сохранить пользователя Ldap в вашей собственной базе данных, обязательно для отношений, без пароля и каким-то образом заставить RefreshUser работать?

Я изменил свою систему, чтобы она работала без сохранения pwd, проверяя при каждом входе в систему, соответствует ли пароль паролю пользователя сервера ldap. Symfony вызывает при каждом запросе метод refreshUser вашего провайдера, у меня есть собственный LDAP-провайдер, чтобы обновить пользователя, используя доктрину из базы данных. Symfony гарантирует, что объект всегда будет обновлен после редактирования.

Проблема в том, что этот метод вызывает метод User Entity getPassword(), который не реализован из-за отсутствия pwd в db.

Я видел способ исправить это, который сохраняет объект в сеансе и каждый раз, когда вызывается refreshUser(), возвращает объект сеанса. Но тогда нет никакого способа, чтобы он всегда обновлялся после редактирования. И я не хочу разрушать инфраструктуру Symfony.

Итак, есть ли способ refreshUser(), возможно, снова вызвать на сервер LDAP и спросить, совпадает ли информация?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
28
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

-РЕШЕНО-

Любой, у кого есть приложение, которое использует аутентификацию сервера ldap и пользовательскую сущность пользователя в базе данных вашего приложения по причинам, но вы не хотите добавлять пароль из соображений безопасности. Вот один ответ:

0. Удалить эквивалент атрибута pwd внутри db

Внутри вашего пользовательского объекта удалите аннотации @Орм, чтобы не сохранять pwd в вашей базе данных. Сохраните атрибут и Getter/Setter.

Например:

//...
private string $password;
//...

1. Добавьте пользовательский LdapProvider

Создайте новый класс, который расширяет Symfony\Component\Ldap\Security\LdapUserProvider. Возможно, вам придется обрабатывать DependencyInjections вручную, добавляя свой собственный Provider внутри вашего services.yaml:

fullyQualified\NameSpace\CustomLdapProvider:
    arguments:
      - '@Doctrine\ORM\EntityManagerInterface' # I need the EM in __construct
      - '@Symfony\Component\Ldap\Ldap'
      - # baseDn
      - # searchDN
      - # searchPassword
      - # roles
      - # uidKey
      - # filter optionaly, add null
      - # passwordAttribute

Переопределите методы «supportsClass» и «refreshUser» следующим кодом:

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }

        return $this->entityManager->getRepository(User::class)->find($user);
    }

    public function supportsClass(string $class): bool
    {
        return User::class === $class || is_subclass_of($class, User::class) || LdapUser::class === $class || is_subclass_of($class, LdapUser::class);
    }

Ваш метод refreshUser() должен возвращать объект пользователя. В моем случае я просто возвращаю пользователя из базы данных.

Важно, чтобы ваш supportsClass() разрешал LdapUser и вашу собственную сущность пользователя, поскольку при первом входе в систему вы получите пользователя с сервера ldap, которым является Symfony\Component\Ldap\Security\LdapUser.

2. Добавьте EventSubscriber в InteractiveLogin

Теперь вам нужно создать собственного пользователя, если его еще нет, затем продолжите его вход в систему с помощью собственного пользовательского объекта.

Создайте новый класс, расширяющий Symfony\Component\EventDispatcher\EventSubscriberInterface, и используйте событие onInteractiveLogIn.

    public static function getSubscribedEvents()
    {
        return [
            SecurityEvents::INTERACTIVE_LOGIN => [
                ['onInteractiveLogIn', 0],
            ],
        ];
    }

Внутри onInteractiveLogIn() вам нужно реализовать свой способ создания нового пользовательского объекта User, если он не найден и сохранен. Также создайте новый Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; для входа.

Мой пример:

 public function onInteractiveLogIn(InteractiveLoginEvent $interactiveLoginEvent)
    {
        $ldapUser = $interactiveLoginEvent->getAuthenticationToken()->getUser();
        if (!($ldapUser instanceof LdapUser)) {
            return;
        }
        $localUser = // find local User with LdapUser credentials (Query);

        if (!$localUser) {
            // no custom user found, create own
            $localUser = new User();
            //...
        }
        // since we do not have pwd, fill it with anything to generate random token
        $rmdBytes = random_bytes(32);
        $localUser->setPassword($rmdBytes);

        $this->entityManager->persist($localUser);
        $this->entityManager->flush();

        // login user with new created/already found custom user entity
        $token = new UsernamePasswordToken($localUser, $rmdBytes, 'main', $localUser->getRoles());
        $this->tokenStorage->setToken($token);
    }

Важно: onInteractiveLogIn уже подтверждает, что введенный pwd равен реальному pwd ldap.

3. Реализовать собственный способ обновления пользователя

Поскольку Symfony вызывает при каждом новом запросе метод refreshUser() для предоставления всегда свежего объекта данных, нам нужно переопределить поведение по умолчанию.

Ваша User Организация должна реализовать Symfony\Component\Security\Core\User\EquatableInterface.

Там вы можете изменить способ сравнения при вызове refreshUser() нового обновленного пользователя и исходного пользователя. По умолчанию используется пароль, но, поскольку у нас нет пароля, мы не хотим такого поведения.

В этом примере я сравниваю UserIdentifieres, поскольку они уникальны:

    public function isEqualTo(UserInterface $user)
    {
        return $this->getUserIdentifier() === $user->getUserIdentifier();
    }
  1. Готово, протестируйте.

Теперь у вас должна быть возможность войти в систему без сохранения pwd в вашей собственной базе данных. Новая система будет вызывать при каждом входе в систему сервер Ldap и запрашивать пользователя с заданными учетными данными. Если затем войти в систему, он больше не будет вызывать сервер, вместо этого автоматически обновит пользователя, если он соответствует isEqualTo().

Другие вопросы по теме