# Смена паролей LDAP через админку ## Возможности Теперь можно менять пароли пользователей LDAP прямо через Django админ-панель! ### Добавлено в LdapUser модель: 1. **Поле `unicode_pwd`** (write-only) - для записи паролей в AD 2. **Метод `set_password(new_password)`** - установка пароля администратором 3. **Метод `change_password(old_password, new_password)`** - смена пароля пользователем ### Добавлено в админку: 1. **Кнопка "🔑 Изменить пароль"** в карточке пользователя 2. **Action "🔑 Изменить пароль выбранных пользователей"** в списке ## Как использовать ### Вариант 1: Через карточку пользователя (РЕКОМЕНДУЕТСЯ ⭐) 1. Откройте `/admin/employees/ldapuser/` 2. **Кликните** на нужном пользователе (откроется карточка) 3. Прокрутите до секции **"⚙️ Управление учетной записью"** 4. Нажмите кнопку **"🔑 Изменить пароль"** 5. Введите новый пароль (минимум 7 символов) 6. Подтвердите пароль 7. Нажмите **"Изменить пароль"** **Результат:** - Пароль изменён в LDAP (Active Directory) - Пароль автоматически синхронизирован в Django БД (если есть связь через `employee_number`) - Вы вернётесь на страницу редактирования пользователя **Преимущества:** - ✅ Удобнее - не нужно искать пользователя в списке и выбирать action - ✅ Быстрее - сразу видно, какого пользователя редактируем - ✅ Безопаснее - меньше шансов ошибиться с выбором пользователя ### Вариант 2: Через action в списке (массовая операция) 1. Откройте `/admin/employees/ldapuser/` 2. Выберите одного или нескольких пользователей (чекбоксы) 3. В dropdown "Действие" выберите **"🔑 Изменить пароль выбранных пользователей"** 4. Нажмите "Выполнить" 5. Введите новый пароль (минимум 7 символов) 6. Подтвердите пароль 7. Нажмите "Изменить пароль" **Результат:** - Пароль изменён в LDAP (Active Directory) - Пароль автоматически синхронизирован в Django БД (если есть связь через `employee_number`) - Вы получите сообщение об успехе или ошибке **Когда использовать:** - При необходимости сменить пароль сразу нескольким пользователям - Для массовых операций (например, сброс паролей всем новым сотрудникам) ### Вариант 3: Программно через ORM ```python from employees.ldap.orm_models import LdapUser # Найти пользователя user = LdapUser.objects.get(sam_account_name='ivanov_i') # Установить новый пароль (админ) user.set_password('NewSecurePass123!') # Или сменить пароль (требует старый пароль) user.change_password('OldPass123', 'NewSecurePass123!') 4 # НЕ нужно вызывать .save() — пароль уже изменён в AD! ``` ### Вариант 3: Через Django Shell ```bash cd /home/lizerk/Dev/EUSRR/backend .venv/bin/python manage.py shell ``` ```python from employees.ldap.orm_models import LdapUser from employees.models import Employee # Найти LDAP пользователя ldap_user = LdapUser.objects.get(sam_account_name='ivanov_i') # Установить пароль ldap_user.set_password('NewPass123!') # Синхронизировать с Django (опционально) if ldap_user.employee_number: emp = Employee.objects.get(pk=int(ldap_user.employee_number)) emp.set_password('NewPass123!') emp.save(update_fields=['password']) print(f"✅ Пароль синхронизирован для {emp.email}") ``` ## Требования к паролю Active Directory политика по умолчанию: - ✅ Минимум **7 символов** (обычно 8+) - ✅ Буквы **верхнего и нижнего** регистра - ✅ **Цифры** - ✅ **Специальные символы** (рекомендуется) - ❌ НЕ должен содержать имя пользователя - ❌ НЕ должен быть в истории паролей ## Обработка ошибок ### ValueError ``` Пароль не соответствует политике сложности Active Directory ``` **Решение:** Используйте более сложный пароль (комбинация букв, цифр, спецсимволов) ### ValueError ``` Пароль слишком короткий ``` **Решение:** Увеличьте длину пароля (минимум 7-8 символов) ### DirectoryLdapError ``` Не удалось установить пароль: {...} ``` **Причины:** - Отсутствует SSL/TLS соединение с AD - Недостаточно прав у сервисной учётки - Проблемы с подключением к LDAP ## Безопасность ⚠️ **Важно:** - Пароли передаются через защищённое LDAP соединение (SSL/TLS) - В БД Django хранится только хэш (не plaintext) - В LDAP пароль хранится в защищённом виде (невозможно прочитать) - Логируются только попытки смены пароля (без самого пароля) ## Интеграция с существующим функционалом Эта функция **дополняет**, а не заменяет: - `UserService.update_user(emp, changes={'password': '...'})` - работает как и раньше - Django admin кнопка "Изменить пароль" для Employee - работает, но **НЕ синхронизирует** с LDAP автоматически Для **автоматической синхронизации** при смене пароля через стандартную админку Employee нужно добавить переопределение метода (см. предыдущее обсуждение). ## Техническая информация ### Как это реализовано 1. **LdapUser.set_password()** вызывает `UserPasswordService.set_password()` 2. Сервис использует `conn.extend.microsoft.modify_password()` (AD extended operation) 3. Это более надёжно, чем прямая запись в атрибут `unicodePwd` 4. Политика паролей AD проверяется автоматически 5. При ошибках возвращаются понятные сообщения ### Поле unicode_pwd - **Тип:** `CharField` (но пустое по умолчанию) - **Write-only:** можно записать, нельзя прочитать - **Кодировка:** UTF-16-LE с кавычками (обрабатывается автоматически) - **Использование:** Не рекомендуется напрямую, используйте `.set_password()` ## Тестирование ```python # В Django shell from employees.ldap.orm_models import LdapUser # Создать тестового пользователя (если есть) user = LdapUser.objects.get(sam_account_name='test_user') # Попробовать сменить пароль try: user.set_password('TestPass123!') print("✅ Пароль успешно изменён") except ValueError as e: print(f"❌ Ошибка валидации: {e}") except Exception as e: print(f"❌ Ошибка LDAP: {e}") ``` ## История изменений **23.03.2026:** - ✅ Добавлено поле `unicode_pwd` в `LdapUser` - ✅ Добавлены методы `set_password()` и `change_password()` - ✅ Добавлен action "🔑 Изменить пароль" в список пользователей - ✅ **Добавлена кнопка "🔑 Изменить пароль" в карточку пользователя** ⭐ - ✅ Создан шаблон `admin/ldap_change_password.html` для массовой смены - ✅ Создан шаблон `admin/ldap_user_password_change.html` для индивидуальной смены - ✅ Автоматическая синхронизация с Django Employee при смене пароля