61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
"""
|
||||
|
|
Вспомогательная логика портала:
|
|||
|
|
- получение списка AD-групп текущего пользователя (из объекта django-auth-ldap)
|
|||
|
|
- подбор доступных Resource по этим группам
|
|||
|
|
- выпуск короткоживущего подписанного токена для backend admin panel
|
|||
|
|
"""
|
|||
|
|
import time
|
|||
|
|
from typing import Iterable
|
|||
|
|
|
|||
|
|
import jwt
|
|||
|
|
from django.conf import settings
|
|||
|
|
|
|||
|
|
from .models import Resource, ResourceGroup
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_user_ad_groups(user) -> set[str]:
|
|||
|
|
"""
|
|||
|
|
django-auth-ldap прикрепляет к user объект `ldap_user` с атрибутом group_names
|
|||
|
|
(набор cn всех групп, в которых состоит пользователь в AD).
|
|||
|
|
Для локального суперпользователя (не через LDAP) атрибута не будет —
|
|||
|
|
возвращаем пустой набор, дальше он видит только ресурсы, явно открытые ModelBackend-группам.
|
|||
|
|
"""
|
|||
|
|
ldap_user = getattr(user, "ldap_user", None)
|
|||
|
|
if ldap_user is None:
|
|||
|
|
return set()
|
|||
|
|
return set(ldap_user.group_names)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_available_resources(user) -> Iterable[Resource]:
|
|||
|
|
if user.is_superuser:
|
|||
|
|
return Resource.objects.filter(is_active=True).select_related("group")
|
|||
|
|
|
|||
|
|
ad_groups = get_user_ad_groups(user)
|
|||
|
|
if not ad_groups:
|
|||
|
|
return Resource.objects.none()
|
|||
|
|
|
|||
|
|
group_ids = ResourceGroup.objects.filter(ad_group_name__in=ad_groups).values_list("id", flat=True)
|
|||
|
|
return Resource.objects.filter(group_id__in=group_ids, is_active=True).select_related("group")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def user_can_access_resource(user, resource: Resource) -> bool:
|
|||
|
|
if user.is_superuser:
|
|||
|
|
return True
|
|||
|
|
return resource.group.ad_group_name in get_user_ad_groups(user)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def issue_resource_token(user, resource: Resource) -> str:
|
|||
|
|
"""
|
|||
|
|
Короткоживущий JWT, который backend admin panel может провалидировать
|
|||
|
|
тем же RESOURCE_TOKEN_SECRET (см. docs/architecture.md, раздел 6).
|
|||
|
|
"""
|
|||
|
|
now = int(time.time())
|
|||
|
|
payload = {
|
|||
|
|
"sub": user.username,
|
|||
|
|
"email": getattr(user, "email", ""),
|
|||
|
|
"group": resource.group.ad_group_name,
|
|||
|
|
"resource": resource.slug,
|
|||
|
|
"iat": now,
|
|||
|
|
"exp": now + settings.RESOURCE_TOKEN_TTL_SECONDS,
|
|||
|
|
}
|
|||
|
|
return jwt.encode(payload, settings.RESOURCE_TOKEN_SECRET, algorithm="HS256")
|