BREAKING CHANGES: - Department.head автоматически очищается при увольнении руководителя - LDAP managedBy атрибут очищается при увольнении Fixes: - DN не перемещался при восстановлении сотрудника (Dismissed → Users) - DN не перемещался при увольнении сотрудника без отделов - Ошибка при увольнении из множественных отделов (двойной modify_dn) - Неправильные URL patterns для LDAP моделей в админке - Двойное кодирование DN в редиректе смены пароля Features: - Добавлен метод _ensure_ldap_dn_location для гарантированного перемещения DN - Добавлена проверка already_there в sync_department_member_to_ldap - Управление паролями LDAP пользователей через админку: * Кнопка смены пароля в карточке пользователя * Массовое действие смены пароля * Автосинхронизация с Django password hash - Автоочистка Department.head и LDAP managedBy при увольнении руководителя - Добавлены методы set_password() и change_password() в LdapUser Changed: - Переписан сигнал sync_department_member_to_ldap с реальными методами - Исправлены URL patterns: ldap_* → employees_*
9.2 KiB
9.2 KiB
Смена паролей LDAP через админку
Возможности
Теперь можно менять пароли пользователей LDAP прямо через Django админ-панель!
Добавлено в LdapUser модель:
- Поле
unicode_pwd(write-only) - для записи паролей в AD - Метод
set_password(new_password)- установка пароля администратором - Метод
change_password(old_password, new_password)- смена пароля пользователем
Добавлено в админку:
- Кнопка "🔑 Изменить пароль" в карточке пользователя
- Action "🔑 Изменить пароль выбранных пользователей" в списке
Как использовать
Вариант 1: Через карточку пользователя (РЕКОМЕНДУЕТСЯ ⭐)
- Откройте
/admin/employees/ldapuser/ - Кликните на нужном пользователе (откроется карточка)
- Прокрутите до секции "⚙️ Управление учетной записью"
- Нажмите кнопку "🔑 Изменить пароль"
- Введите новый пароль (минимум 7 символов)
- Подтвердите пароль
- Нажмите "Изменить пароль"
Результат:
- Пароль изменён в LDAP (Active Directory)
- Пароль автоматически синхронизирован в Django БД (если есть связь через
employee_number) - Вы вернётесь на страницу редактирования пользователя
Преимущества:
- ✅ Удобнее - не нужно искать пользователя в списке и выбирать action
- ✅ Быстрее - сразу видно, какого пользователя редактируем
- ✅ Безопаснее - меньше шансов ошибиться с выбором пользователя
Вариант 2: Через action в списке (массовая операция)
- Откройте
/admin/employees/ldapuser/ - Выберите одного или нескольких пользователей (чекбоксы)
- В dropdown "Действие" выберите "🔑 Изменить пароль выбранных пользователей"
- Нажмите "Выполнить"
- Введите новый пароль (минимум 7 символов)
- Подтвердите пароль
- Нажмите "Изменить пароль"
Результат:
- Пароль изменён в LDAP (Active Directory)
- Пароль автоматически синхронизирован в Django БД (если есть связь через
employee_number) - Вы получите сообщение об успехе или ошибке
Когда использовать:
- При необходимости сменить пароль сразу нескольким пользователям
- Для массовых операций (например, сброс паролей всем новым сотрудникам)
Вариант 3: Программно через ORM
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
cd /home/lizerk/Dev/EUSRR/backend
.venv/bin/python manage.py shell
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 нужно добавить переопределение метода (см. предыдущее обсуждение).
Техническая информация
Как это реализовано
- LdapUser.set_password() вызывает
UserPasswordService.set_password() - Сервис использует
conn.extend.microsoft.modify_password()(AD extended operation) - Это более надёжно, чем прямая запись в атрибут
unicodePwd - Политика паролей AD проверяется автоматически
- При ошибках возвращаются понятные сообщения
Поле unicode_pwd
- Тип:
CharField(но пустое по умолчанию) - Write-only: можно записать, нельзя прочитать
- Кодировка: UTF-16-LE с кавычками (обрабатывается автоматически)
- Использование: Не рекомендуется напрямую, используйте
.set_password()
Тестирование
# В 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 при смене пароля