Перевоплощение (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 Конфиденциальность¶
Перевоплощение НЕ блокируется конфиденциальностью. Администратор, перевоплотившись, видит конфиденциальные задачи целевого пользователя (если тот является подписчиком).
Это by design — конфиденциальность защищает от коллег, не от администратора.
7.2 Шифрование¶
Перевоплощение блокируется шифрованием. При перевоплощении проверяются права обоих — и инициатора, и целевого пользователя. Оба должны иметь право «Просмотр зашифрованных задач», чтобы увидеть расшифрованные данные.
Что скрыто при отсутствии прав у одного из двух: - Зашифрованные ДП — пустые / скрытые - Текст задачи — не отображается - Файлы — недоступны для скачивания - Комментарии — текст скрыт
Исторический баг (исправлен в 2.267.353): МТФ передавал null вместо oldSessionUserId → проверка шифрования обходилась. Исправлено в 103 файлах (backend + frontend).
7.3 Матрица¶
| Защитный механизм | Замещение | Перевоплощение |
|---|---|---|
| Конфиденциальность | Заблокировано | Доступ есть |
| Шифрование | Заблокировано | Заблокировано (оба должны иметь право) |
| Конфиденциальность + шифрование | Заблокировано | Заблокировано |
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 |
Спека 1f-real-user-id: reference/api/auth-operations-guide.md § 1.5. Применение в Анфисе: domains/ai/architecture/permission-enforcement.md.
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 |