Corp/backend/eusrr_backend/middleware.py
lizerk 75662ec7ea feat(ldap): Полная миграция на django-ldapdb ORM с миксинами и Django Admin
LDAP ORM модели (orm_models.py):
================================
✅ Применены миксины ModifyDnMixin и LdapSyncStateMixin ко всем моделям
✅ LdapUser - поддержка modify_dn + автоуправление LdapSyncState
✅ LdapGroup - поддержка modify_dn для перемещения групп
✅ LdapOrganizationalUnit - поддержка modify_dn для реорганизации

Миксины (mixins.py) - НОВЫЙ ФАЙЛ:
=================================
✅ ModifyDnMixin - автоматический modify_dn при изменении base_dn
   • Отслеживает изменения base_dn
   • Выполняет LDAP modify_dn с newsuperior
   • Обновляет _saved_dn для корректного последующего save()
   • Использование: user.base_dn = new_dn; user.save()

✅ LdapSyncStateMixin - автоуправление LdapSyncState
   • Автоматически создает/обновляет LdapSyncState при save()
   • Автоматически удаляет LdapSyncState при delete()
   • Настройки: _sync_model_name, _sync_pk_field

Django Admin для LDAP (admin.py) - НОВЫЙ ФАЙЛ:
==============================================
✅ LdapUserAdmin - полноценная админка для LDAP пользователей
   • List display: CN, SAM, email, Django Employee link, sync status
   • Search: по CN, SAM, email, имени, фамилии
   • Filters: по userAccountControl
   • Actions синхронизации:
     - sync_from_ldap_to_django (LDAP → Django)
     - sync_from_django_to_ldap (Django → LDAP)
     - show_sync_diff (сравнение данных)
   • Fieldsets: идентификация, персональные данные, контакты, UAC, группы
   • DN форматирование с подсветкой компонентов
   • Sync status indicators с иконками

Django Admin для Employee (employees/admin.py):
===============================================
✅ Добавлены зеркальные actions синхронизации:
   • sync_from_django_to_ldap - создание/обновление в LDAP
     - Автоматическое создание LDAP пользователя если не существует
     - Генерация временного пароля
     - Установка is_ldap_managed = True
   • sync_from_ldap_to_django - обновление из LDAP
   • show_sync_diff - сравнение Django ↔ LDAP
✅ Импорт django.contrib.messages для уведомлений

Сервисы LDAP (services/):
=========================
✅ UserService - полная миграция на ORM для UPDATE операций
✅ GroupService - использование ORM для модификаций
✅ DepartmentService - ORM для обновления OU
✅ PositionService - ORM для групп позиций

Тесты (tests/unit/):
===================
✅ test_user_service.py - обновлены под ORM
✅ test_group_service.py - обновлены под ORM
✅ test_position_service.py - обновлены под ORM
✅ conftest.py - добавлены фикстуры для ORM моделей

Authentication (auth_backends.py):
=================================
✅ EmailOrPhoneBackend - добавлено подробное debug логирование
   • Логирование email/phone lookup
   • Логирование is_active проверки
   • Логирование password check с hash prefix
✅ SuperuserOnlyBackend - добавлено debug логирование
   • Логирование parent auth результата
   • Логирование is_superuser проверки

API (api/auth/serializers.py):
==============================
✅ PhoneOrEmailTokenObtainPairSerializer - исправлен KeyError
   • Добавлена проверка credentials перед super().validate()
   • Явный AuthenticationFailed при отсутствии учетных данных

Middleware (middleware.py):
===========================
✅ Очистка от устаревшего кода (305 → 102 строки)
   • ❌ Удалена EmailVerificationMiddleware (не используется)
   • ❌ Удалена RegistrationIPRestrictionMiddleware (не используется)
   • ❌ Удалены все ссылки на namespace 'auth_front'
   • ✅ Возврат 403 для неавторизованных вместо редиректа

Settings (settings.py):
=======================
✅ LOGIN_URL изменен с 'auth_front:login' на '/admin/login/'
✅ Добавлено DEBUG логирование для:
   • django.contrib.auth
   • eusrr_backend.auth_backends

Миграции:
=========
✅ Удалены старые миграции LDAP моделей (0042, 0043)
✅ Добавлена миграция LdapSyncQueue (0042_ldapsyncqueue.py)

Документация:
=============
✅ ADMIN_GUIDE.md - руководство по использованию LDAP Admin
✅ docs/guides/ldap-orm-mixins-usage.md - usage guide для миксинов
✅ docs/completed/ldap-orm-create-support.md - документация ORM миграции
✅ docs/in-progress/LDAP_ORM_MIGRATION_PLAN.md - план миграции

Инфраструктура (__init__.py):
=============================
✅ Добавлен импорт admin для авторегистрации
✅ Экспорт ORM моделей (LdapUser, LdapGroup, LdapOrganizationalUnit)

ИТОГО:
======
• Полная миграция с ldap3 на django-ldapdb ORM для UPDATE/MOVE/DELETE
• Унификация: один подход для всех LDAP операций через модели
• Автоматизация: синхронизация состояния и перемещения через миксины
• UI: полноценный Django Admin для управления LDAP объектами
• Отладка: расширенное логирование аутентификации
• Чистота: удален устаревший код middleware и миграций
• Тесты: 29 passed, 0 failed, 18 skipped

Breaking Changes: НЕТ - обратная совместимость сохранена
2026-03-19 22:33:06 +03:00

100 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# backend/eusrr_backend/middleware.py
"""
Кастомные middleware для проекта EUSRR.
Минимальный набор для работы Django Admin + REST API.
"""
from django.conf import settings
class AuthRequiredMiddleware:
"""
Базовая защита: неавторизованные пользователи не могут заходить куда-либо,
кроме API и админки (которые управляют аутентификацией сами).
Разрешенные зоны без аутентификации:
- /api/ - REST API с JWT/Token аутентификацией
- /admin/ - Django Admin со своей системой аутентификации
- /static/ - статические файлы
- /media/ - медиафайлы
"""
EXEMPT_PREFIXES = (
"/api/", # REST API управляет своей аутентификацией
"/admin/", # Django Admin использует встроенную аутентификацию
"/static/", # Статика
"/media/", # Медиа
)
def __init__(self, get_response):
self.get_response = get_response
self.allowed_prefixes = tuple(
getattr(settings, "AUTH_REQUIRED_EXEMPT_PREFIXES", self.EXEMPT_PREFIXES)
)
def __call__(self, request):
# Аутентифицированные пользователи проходят везде
if request.user.is_authenticated:
return self.get_response(request)
path = request.path_info
# Пропускаем разрешенные префиксы - они сами управляют аутентификацией
# Django Admin сам редиректит на /admin/login/ если нужно
if any(path.startswith(p) for p in self.allowed_prefixes):
return self.get_response(request)
# Все остальное - 403 Forbidden для неаутентифицированных
from django.http import HttpResponseForbidden, JsonResponse
# Для API запросов возвращаем JSON
if request.headers.get('Accept', '').startswith('application/json'):
return JsonResponse(
{"detail": "Authentication required"},
status=403
)
# Для браузерных запросов - HTML 403
return HttpResponseForbidden("403 Forbidden: Authentication required")
class CacheControlMiddleware:
"""
Добавляет правильные заголовки Cache-Control для HTML-страниц.
Стратегия:
- HTML страницы: private cache на 60 секунд (только для браузера)
- API: обрабатывается на уровне DRF
- Статика/медиа: обрабатывается веб-сервером
"""
NO_CACHE_PREFIXES = (
"/api/", # API управляет своим кэшем
"/admin/", # Админка всегда свежая
"/static/", # Обрабатывается веб-сервером
"/media/", # Обрабатывается веб-сервером
)
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
# Применяем только к успешным HTML GET-запросам
if (
response.status_code == 200
and request.method == "GET"
and response.get("Content-Type", "").startswith("text/html")
):
path = request.path_info
# Проверяем исключения
if not any(path.startswith(p) for p in self.NO_CACHE_PREFIXES):
# Если заголовок уже установлен - не перезаписываем
if not response.has_header("Cache-Control"):
response["Cache-Control"] = "private, max-age=60"
return response