Перейти к содержанию

Перевоплощение (Impersonation)

Источники: core (AuthController, PermissionsService, TokenModificationsService, TransformationLogEntity), архивное руководство администратора: alien.md

1. Что это

Перевоплощение — механизм, позволяющий администратору (или пользователю с соответствующими правами) работать в системе от имени другого пользователя. Видит то же, что видит целевой пользователь. Используется для отладки прав, настройки UI, поддержки.

Не путать с замещением — замещение передаёт права, перевоплощение создаёт новую сессию от имени целевого пользователя. См. substitution.md.

2. Кто может перевоплощаться

Три способа получить право:

# Способ Условие
1 Системная группа «Администраторы» Пользователь в группе Administrators И группе не выдано спецправо DENYIMPERSONATION
2 Право группы на группу Право «Перевоплощаться в членов группы» (ActionID = Helpers.ActionsGroupOnGroup.Impersonate). Не-админ → не может перевоплощаться в админа
3 EWS (Exchange) Для синхронизации календаря. Настройка CalendarExchangeUseImpersonate или общая настройка «Использовать перевоплощение»

Алгоритм проверки (PermissionsService.CanImpersonate)

1. CheckSpecialPermission(userId, DENYIMPERSONATION) → true? → return false
2. IsUserGod(userId) → true? → return true  (админ может в любого)
3. IsUserGod(targetUserId) → true? → return false  (не-админ не может в админа)
4. CheckUserOnUserPermission(userId, targetUserId, Impersonate) → проверка прав группы на группу

Код: core/TCClassLib/Permissions/PermissionsService.cs:213-235

3. Спецправо DENYIMPERSONATION

Специальное право, назначаемое группе. Если пользователь входит хотя бы в одну группу с этим правом — перевоплощение для него запрещено (даже если он администратор).

Ограничение: нельзя назначить DENYIMPERSONATION группе «Администраторы».

Мнемоника: DENYIMPERSONATION в таблице GroupPermissionsToSpecialActions.

Код: core/Valhalla.Integration/Constants/SpecialActions.cs:65, AdminPermissionsService.cs:77-107

4. API

4.1 Начать перевоплощение

POST /api/auth/{userId}/impersonate

Ответы: - 204 No Content — успешно, последующие запросы от имени целевого пользователя - 403 Forbidden — нет прав или попытка вложенного перевоплощения

Ограничение: вложенное перевоплощение запрещено. Если Context.ImpersonatedUserId.HasValue — возвращается 403.

Код: core/UniForm/UniForm.Api/Controllers/OldApi/Version2_0/Auth/AuthController.cs:290-317

4.2 Завершить перевоплощение

POST /api/auth/undotransformation

Ответ: 204 No Content — сессия возвращается к реальному пользователю.

Код: AuthController.cs:330-344

5. Механика сессии (JWT)

При перевоплощении: 1. UserAuthenticationService.Impersonate(HttpContext, userId) — создаёт новый JWT 2. В новом JWT: SessionUserId = целевой пользователь, OldUserId = инициатор 3. Поле Context.ImpersonatedUserId доступно всем сервисам для проверки «кто инициатор» 4. Все действия выполняются от имени целевого пользователя 5. При StopImpersonation — JWT возвращается к исходному пользователю 6. Проверяется наличие действующей лицензии у целевого пользователя. Если лицензия отсутствует, перевоплощение не выполняется. 7. JWT перевыпускается уже после успешного прохождения этой проверки.

6. Аудит (TransformationLog)

Каждое перевоплощение логируется в таблицу TransformationLog.

Колонка Тип Описание
TransformationLogID int, PK, Identity ID записи
OldUserID int, FK → Users Инициатор перевоплощения
NewUserID int, FK → Users Целевой пользователь
TransformationTime datetime Время события
UserComputerName varchar(300) Hostname / IP инициатора
IsReturn bit 0 = перевоплощение, 1 = возврат
UserAgent varchar(512), NULL User-Agent браузера

Запись создаётся при: перевоплощении (IsReturn=0) и возврате (IsReturn=1).

Просмотр: вкладка «Журнал» в профиле пользователя. Видят: администраторы (в журналах всех), пользователь (в своём журнале).

Код: core/Valhalla.Authentication/Authentication/Token/Jwt/TokenModificationsService.cs:191-216

7. Защита данных при перевоплощении

7.1 Конфиденциальность

С версии 2.268.326 перевоплощение блокируется конфиденциальностью. При перевоплощении проверяются права обоих пользователей — инициатора (oldSessionUserId) и целевого (sessionUserId) — через TaskPermissionsService.CheckConfidentialTaskAccess. Если целевой пользователь — подписчик конфиденциальной задачи, а перевоплощающийся администратор — нет, содержимое скрывается и задача фильтруется из ключевых списков.

Что скрывается:

  • Текст задачи → (Текст задачи скрыт) (Language.task_TaskTextIsHidden)
  • Текст комментариев → (Комментарий скрыт) (Language.task_CommentIsHidden)
  • Файлы — недоступны через общий Permissions.CheckTaskAccess(sessionUserId, taskId, impersonatedUserId), теперь учитывающий оба user-id
  • Попытка PostComment / ForwardComments к конфиденциальной задаче — AccessDeniedException

Что фильтруется (задача исчезает из списков):

  • Ленты задач, комментариев, тредов: ShowTasksFeed, ShowCommentsFeed, ShowTaskThreadsFeed
  • История просмотров: UserWebHistoryService
  • Глобальный поиск: TasksFeedSearchService, InDbSimpleSearch

Что остаётся видимым (известные ограничения текущей итерации, по UPD задачи #2076733):

  • Избранное — задача в списке остаётся, заголовок заменяется на (Текст задачи скрыт)
  • Счётчики непрочитанных и сигнальные события — продолжают учитывать конфиденциальные чаты; специфичных правок счётчиков в этой итерации не было
  • Push-уведомления, всплывающие уведомления, события о новом сообщении — не блокируются в этой итерации; планируется отдельной задачей
  • Аудит блокировок (журнал попыток доступа из-под перевоплощения) — не реализован; планируется отдельно

7.2 Шифрование

Перевоплощение блокируется шифрованием. При перевоплощении проверяются права обоих — и инициатора, и целевого пользователя. Оба должны иметь право «Просмотр зашифрованных задач», чтобы увидеть расшифрованные данные.

Что скрыто при отсутствии прав у одного из двух: - Зашифрованные ДП — пустые / скрытые - Текст задачи — не отображается - Файлы — недоступны для скачивания - Комментарии — текст скрыт

Исторический баг (исправлен в 2.267.353): МТФ передавал null вместо oldSessionUserId → проверка шифрования обходилась. Исправлено в 103 файлах (backend + frontend).

7.3 Матрица

Защитный механизм Замещение Перевоплощение
Конфиденциальность Заблокировано Заблокировано (с 2.268.326)
Шифрование Заблокировано Заблокировано (оба должны иметь право)
Конфиденциальность + шифрование Заблокировано Заблокировано

8. UI

В SPA

  • Кнопка перевоплощения: в профиле пользователя (панель инструментов) и в справочнике «Сотрудники» (при наведении)
  • Индикатор перевоплощения: зелёная полоса в верхней панели с именем целевого пользователя
  • Выход: крестик на индикаторе

В мобильном приложении

Перевоплощение доступно. Подробности: ../mobile/README.md.

9. Ограничения

Ограничение Описание
Вложенное перевоплощение Запрещено. Нельзя перевоплощаться, будучи перевоплощённым
Лицензия Для перевоплощения у целевого пользователя должна быть действующая лицензия (не-конкурентная). Проверка выполняется в TokenModificationsService.ChangeUser после CanImpersonate. Если лицензия отсутствует — перевоплощение блокируется.
Не-админ → админ Пользователь без прав God не может перевоплотиться в администратора
DENYIMPERSONATION Блокирует перевоплощение даже для администратора
Нельзя применить DENYIMPERSONATION к группе «Администраторы» Защита от самоблокировки

10. Связанная документация

  • substitution.md — замещение (передача прав, не сессии)
  • business.md §9 — конфиденциальность и шифрование
  • access-check.md — fn_UserTaskPermissionsGeneral (перевоплощение меняет @UserID)
  • архивной инструкции администратора по замещению — инструкция администратора
  • ../users-and-groups/faq-absence-button-visibility.md — специальные права групп

Не путать с системной impersonation для AI-агентов

1f-real-user-id — служебный HTTP-заголовок, через который аутентифицированный системный агент (Анфиса, server-side worker'ы) выполняет запрос от имени пользователя для применения ACL под этого пользователя. Это другой механизм:

User impersonation (этот документ) 1f-real-user-id
Кто использует Администратор через UI AI-агент / server-side worker через HTTP
Цель Отладка прав, поддержка Применение прав asker'а к read-операциям
Создаёт сессию Да (новый JWT с ImpersonatedUserId) Нет — per-request override SessionUserId
Логируется TransformationLogEntity На уровне tool-handler'а (AnfisaConversationLog)
API POST /api/auth/{userId}/impersonate Header в любом GET/POST с PAT/JWT

11. Источники кода

Объект Файл
API endpoint core/UniForm/UniForm.Api/Controllers/OldApi/Version2_0/Auth/AuthController.cs:290
CanImpersonate core/TCClassLib/Permissions/PermissionsService.cs:213
DENYIMPERSONATION core/Valhalla.Integration/Constants/SpecialActions.cs:65
AdminPermissionsService core/TCClassLib/Permissions/AdminPermissionsService.cs:77
TransformationLogEntity core/TCDataAccess/Kernel/Domain/Entities/TransformationLogEntity.cs
JWT обработка core/Valhalla.Authentication/Authentication/Token/Jwt/TokenModificationsService.cs:191