Перейти к основному содержимому

POST /api/admin/v1/users/{userId}/security/reset — Ручной сброс факторов входа (admin)

Назначение

Операция «ручная верификация/сброс» из ADR-0053: пользователь потерял доступ (забыл пароль/пин, утратил устройство 2FA, залочен по попыткам) и его личность подтверждена вручную (Служба заботы по регламенту верификации → админ выполняет сброс). Сбрасывает выбранные факторы входа (PasswordHash/PinCodeHash/IsTwoFactorEnabled/lockout) и отзывает все активные сессии — после сброса пользователь входит заново штатным СМС-flow по своему номеру и настраивает факторы с нуля.

Секреты не принимаются

Новые значения пароля/пин-кода API не принимает (запрещено: plaintext-секреты через admin-канал) — только сброс в «не задано».

Metadata

ПолеЗначение
Сервис/контекстidentity
API areaadmin (ADR-0053)
Feature groupadmin-users
Статусdraft
Документdocs/06-services/identity/api/admin/reset-user-security.md

Актор и доступ

ПроверкаЗначение
Actor typeExternalSystem (система администрирования; m2m client-credentials)
Auth policy / Permissionspolicy AdminSystemOnly; в системе администрирования операция доступна после процедуры ручной верификации личности (граница admin-identity, ADR-0053)
Scope (RBAC)платформа (кросс-tenant)
Tenant isolationbypass tenant-фильтров под system-scope
Auditобязателен: deep audit — actor, userId, какие факторы сброшены, VerificationTicketId

HTTP-контракт

ПолеЗначение
MethodPOST
Route/api/admin/v1/users/{userId}/security/reset
Success status200
Idempotency headerIdempotency-Key (Guid; обязателен)
CorrelationOTel trace (traceparent); X-Admin-User-Id — обязателен

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
UserIdrouteGuidДа!= Guid.Empty
ResetPasswordbodyboolДаPasswordHash → null
ResetPinCodebodyboolДаPinCodeHash → null
DisableTwoFactorbodyboolДаIsTwoFactorEnabled → false
ResetLockoutbodyboolДаFailedAccessAttempts → 0, LockoutUntil → null
VerificationTicketIdbodyGuidДа!= Guid.Empty; id тикета заботы, где зафиксирована ручная верификация личности (support-контекст; существование identity не проверяет — принадлежит admin-процессу, только аудит)audit
Commentbodystring?Нет≤ 1024только audit
AdminUserIdheader X-Admin-User-IdGuidДа!= Guid.Emptyaudit-stamping
IdempotencyKeyheader Idempotency-KeyGuidДа!= Guid.Empty
Кросс-полевое правило

Хотя бы один из ResetPassword/ResetPinCode/DisableTwoFactor/ResetLockout = true (иначе ValidationError).

Модель ответа AdminResetUserSecurityResult

ПолеТипОбязательностьИсточникMaskingОписание
UserIdGuidДаUserEntity.IdПользователь.
PasswordResetboolДавычисление (флаг ∧ был задан)Пароль фактически сброшен.
PinCodeResetboolДато жеПин-код фактически сброшен.
TwoFactorDisabledboolДато же2FA фактически выключена.
LockoutResetboolДато жеLockout фактически снят.
RevokedSessionsCountintДабатч-отзывОтозвано активных сессий.
VersionlongДаUserEntity.VersionВерсия после мутации.
Маскирование

Хэши/секреты в ответ не попадают никогда (правило user.md).

Алгоритм

  1. Контекст и доступ. Операцию выполняет система администрирования (m2m-клиент pin-admin-system, policy AdminSystemOnly) после процедуры ручной верификации личности. Повтор с тем же Idempotency-Key (admin:user-security-reset:{IdempotencyKey}) возвращает сохранённый результат.
  2. Проверка входа и предусловий. Задан хотя бы один флаг сброса, VerificationTicketId не пуст, Comment ≤ 1024 — иначе ValidationError (400). Пользователь UserId существует — иначе IDENTITY_USER_NOT_FOUND (404). Статус ∈ {Active, Invited, Blocked} (сброс заблокированному допустим — готовит вход после unblock); ArchivedIDENTITY_USER_INVALID_STATUS_TRANSITION (409). Для ContactsManagedBy = TalentSync операция допустима: секреты входа локальны для PIN и синком не управляются (talent-replica.md), INV-4 user.md не затрагивается.
  3. Бизнес-правила и переходы. По установленным флагам сбрасываются факторы входа:
    • ResetPassword → пароль снимается (PasswordHash → null, PasswordChangedAt = now, производный флаг hasPassword станет false);
    • ResetPinCode → пин-код снимается (PinCodeHash → null, hasPinCode = false);
    • DisableTwoFactor → 2FA выключается (IsTwoFactorEnabled → false, TwoFactorChangedAt = now) — без СМС-подтверждения (INV-7 user.md описывает self-service flow; admin-сброс — отдельный привилегированный путь, компенсируется ручной верификацией и аудитом);
    • ResetLockout → снимается блокировка попыток (FailedAccessAttempts → 0, LockoutUntil → null, INV-8 снимается). Флаги, для которых фактор и так не задан, — без эффекта (в ответе false); фиксируется вид изменения на каждый применённый сброс.
  4. Что меняется. Учётка обновляется по применённым флагам. Все активные сессии отзываются (INV-S7): Active → Revoked c RevokedReason = PasswordChanged. Висящие одноразовые запросы кодов гасятся: SignInConfirmationRequest в статусе Pending → Superseded (открытые 2FA/смены-контакта flow обнуляются). Правка не должна затирать конкурентное изменение (CONCURRENCY_CONFLICT). Новые значения пароля/пин-кода операция не принимает — только сброс в «не задано».
  5. События. Интеграционных нет: состав публичных полей UserUpsertedKafkaEvent не меняется (секреты не публикуются), права не менялись. Доменные UserSecurityChangedEvent и SessionRevokedEvent — лента админ-аудита/расследований (user.md, user-session.md). Изменение учётки, отзыв сессий, гашение кодов, отметка идемпотентности и audit — в одном согласованном изменении.
  6. Результат. AdminResetUserSecurityResult: UserId, флаги фактически применённого сброса (PasswordReset/PinCodeReset/TwoFactorDisabled/LockoutReset — по состоянию до мутации), RevokedSessionsCount, Version. Хэши/секреты в ответ не попадают.

Диаграмма

Побочные эффекты

ТипДетали
Integration eventsnone (публичный снапшот пользователя не изменился)
External callsnone (СМС не отправляется — пользователь сам инициирует вход)
Cache / projections / searchnone
Notificationsрекомендуемое расширение: уведомление пользователю «факторы входа сброшены поддержкой» — инициируется системой администрирования, не identity

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
ValidationError400Все флаги false / нет VerificationTicketIdОшибка валидации запросаno retry
FORBIDDEN403Клиент не pin-admin-systemДоступ запрещёнno retry
IDENTITY_USER_NOT_FOUND404Пользователь не существуетПользователь не найденno retry
IDENTITY_USER_INVALID_STATUS_TRANSITION409Status = ArchivedПользователь в архивеno retry
CONCURRENCY_CONFLICT409Гонка версийПовторите операциюretry с тем же Idempotency-Key

Acceptance Criteria

  • Given учётка Active с паролем, пином, включённой 2FA и активным lockout, When reset со всеми флагами = true и валидным VerificationTicketId, Then PasswordHash/PinCodeHash → null, IsTwoFactorEnabled = false, lockout снят, все активные сессии отозваны, висящие SignInConfirmationRequest в Pending → Superseded, ответ с PasswordReset/PinCodeReset/ TwoFactorDisabled/LockoutReset = true; секреты в ответ не попадают.
  • Given у учётки не задан пароль, а ResetPassword = true, When reset, Then PasswordReset = false (фактор и так отсутствовал); остальные применённые флаги — по состоянию до мутации.
  • Given все четыре флага false, When reset, Then ValidationError (400) — требуется хотя бы один сброс.
  • Given пустой VerificationTicketId, When reset, Then ValidationError (400).
  • Given учётка Blocked, When reset, Then успех (сброс готовит вход после unblock); статус ArchivedIDENTITY_USER_INVALID_STATUS_TRANSITION (409).
  • Given Talent-managed учётка (ContactsManagedBy = TalentSync), When reset, Then успех — секреты входа локальны для PIN и синком не управляются.
  • Given повтор с тем же Idempotency-Key, When запрос по таймауту, Then сохранённый результат (replay), факторы повторно не трогаются.
  • Given сброс выполнен, Then интеграционные события не публикуются (публичный снапшот не изменён); пользователь входит заново штатным СМС-flow по своему номеру.

Совместимость и наблюдаемость

  • Новые optional-флаги сброса — additive; приём значений секретов — запрещён навсегда (security rule, не совместимостное).
  • Logs: admin-security-reset (userId, применённые флаги, adminUserId, verificationTicketId; без секретов/PII); metrics: identity_admin_operations_total{operation="reset-security"}; traces — OTel; deep audit. Алерт на всплеск операций (возможная компрометация системы администрирования).

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы