SCIM линейки — справочник ресурсов каталога
Актуально для: directory 1.4.0 · Проверено: 30.10.2026 · Написано руками (не генерируется).
Каталог — реализация SCIM 2.0 (RFC 7643/7644) с фиксированным набором сущностей, и единственная дверь к данным
линейки для сервисов, координатора, консоли и клиентов. Дверей «под тип» (/control/policy/*,
/control/legs*, /control/gal*, /control/authz*, /v1/service/{directory/feed, people/changes, …},
/v1/directory/*) у каталога больше нет. Отдельные двери остались только там, где каталог сам действует: вход
(OIDC/SAML/LDAP, credentials/verify, сессии, ключи), схема (/control/schema*), репликация, аудит,
/healthz, /control/about|health|maintenance, а также /control/accounts|groups|objects|units для консоли.
Корень — https://dir.<домен>/scim/v2. Клиентская библиотека сервисов — shared/scim/client (Go).
Кто входит
| Кто | Чем | Что может |
|---|---|---|
| координатор, администратор identity, токен SCIM из консоли, реплика | свой токен | всё: чтение, запись, лента |
сервис платформы (svc:*) | служебный токен, aud identity | чтение всех коллекций и ленты; …/{id}/secrets своих объектов; запись — отказ 403 |
| сервер или сервис как объект | свой токен объекта | только GET …/{id}/secrets своего объекта |
| человек (платформенный токен) | свой токен | режим читателя: GET /Users, /Users/{id}, /Users/{id}/photo, /Schemas, /ResourceTypes, /ServiceProviderConfig |
| администратор по своим грантам | платформенный токен | как координатор (admintoken.go) |
Запись везде — POST, PUT с If-Match (версия в meta.version, W/"<rev>"; расхождение — 412), PATCH
(только Users и Groups), DELETE. Ошибка — документ urn:ietf:params:scim:api:messages:2.0:Error
(status, scimType, detail).
Коллекции
| Коллекция | Класс объекта | Схема | Типы |
|---|---|---|---|
/Users | учётная запись | urn:ietf:params:scim:schemas:core:2.0:User + enterprise + urn:ietf:params:scim:schemas:extension:simpletwo:2.0:User | — |
/Groups | группа | core Group + urn:ietf:params:scim:schemas:extension:simpletwo:2.0:Group | — |
/Units | подразделения (только лента ?since=) | urn:ietf:params:scim:schemas:simple:2.0:Unit | — |
/Servers | server | …simple:2.0:Server | открытый |
/Services | service | …simple:2.0:Service | открытый (secure_access.gateway, …) |
/Sites | site | …simple:2.0:Site | dc, office, geo, gateway_group |
/Policies | policy | …simple:2.0:Policy | политики установки по одной на вид: credentials, sessions, guests, leavers, reviews, terms, app_links, app_passwords, username_retention, telephony, dialplan, legs, photos, branding; шаблоны quota; профили secure_access.* |
/AddressLists | address_list | …simple:2.0:AddressList | — |
/Authz | authz | …simple:2.0:Authz | grants (каталог прав серверной роли, catalogue:<role>), role, assignment (user:<uid>, group:<gid>) |
/Legs | leg | …simple:2.0:Leg | sip-endpoint, panel |
Атрибуты объекта лежат на верхнем уровне документа (name, type, unit, disabled, links, затем
атрибуты класса из схемы расширения). Ссылки — links: [{rel, value, $ref}]: applies_to у политики (цель
root, unit:<id>, group:<id>), visible_to у адресного списка.
Подресурсы объекта: GET|PUT|DELETE …/{id}/secrets/{key} (значения — координатору и самому объекту, факты —
администратору), …/{id}/files/{name}, GET …/{id}/revisions.
Расширение User (…:simpletwo:2.0:User)
Вычисляется при ответе, только чтение: kind (person | guest | bot | room | system), entity, guest,
system, assistant, source, sponsor/owner ({value, display}), expiresAt, extension, site,
phone, telPrimary, dial, formerUserNames, hideFromAddressLists, features (для чего учётка
подготовлена: messaging, calendar, mail, drive, telephony, secure_access), projected, addressLists (в каких
списках), addressBook (какие списки читает), groupNames, roles, leaver (state, legalHold,
responsible, deletedAt), photoHash, addresses (ключи индекса адресов: tel:…, email:…, sip:…).
Атрибуты каталога людей (hire_date, …) — там же, по их SCIM-путям.
«A видит B» = addressBook(A) ∩ addressLists(B) ≠ ∅. «Чей адрес» — GET /Users?filter=…:addresses eq "<ключ>"
(ключи даёт dirschema.AddressLookupKeys).
Расширение Group (…:simpletwo:2.0:Group)
kind, source, handle, address, owner, owners, writers, defaultConvs; members[].display — логин.
Лента по курсору
Каждая коллекция отвечает на ?since=<seq>[&count=<n>][&filter=…]: строки, записанные после позиции
единого счётчика, включая tombstone (…:Replication: {seq, deleted}), в порядке записи. Ответ несёт
…simple:2.0:Replication:head (последняя позиция) и :floor (самый старый ещё хранимый tombstone; курсор ниже
пола — читать с 0). /Users?since= несёт ещё …:simpletwo:2.0:User:provisioning (on|off): смена режима —
читать с 0. Удалённую учётку сервис читает и по id (GET /Users/{id} — tombstone с leaver).
Ответ несёт и …:Replication:next — позицию хранилища, до которой дочитана страница, включая строки, которых
лента не показала (чужой класс на ленте объектов, истёкший tombstone): читатель продолжает с неё, а не с последней
показанной строки. Читается лента в словах черновиков IETF SCIM: ?deltaQuery=true в первый раз, ?deltaToken=<токен> потом,
страницы — ?cursor=<nextCursor> (RFC 9865); последняя страница несёт nextDeltaToken, который читатель
хранит и возвращает как есть — токен непрозрачен. Проход без изменений — 304; позиция, которой лента уже
не помнит (ниже пола или за головой после восстановления) — 400 с scimType: expiredDeltaToken, читатель
начинает заново с deltaQuery=true; нечитаемый токен — 400 invalidValue; удалённая строка несёт
meta.isDeleted: true. /ServiceProviderConfig объявляет pagination (cursor, index, размеры страниц,
cursorTimeout) и deltaQuery (supported, deltaTokenExpiry). Старое ?since=<seq> с …:Replication:head,
:floor и :next остаётся репликам и одной версии перехода. Страница ленты несёт ETag (голова, пол и довески страницы). Читатель, стоящий на голове, шлёт его как
If-None-Match и получает 304 без тела — «ничего нового» стоит каталогу сравнения головы, а не страницы.
Страницы лент идут не более двух одновременно на экземпляр: третья ждёт секунду и получает 503 с
Retry-After: 2; любой запрос, не уложившийся в 8 с, получает 503 с Retry-After: 5 — раньше, чем читатель
отвалится по своему таймауту. Читателю положено ходить раз в минуту с разбросом и удваивать паузу после отказа.
Вычисляемые ресурсы (только чтение)
| Ресурс | Фильтр | Ответ |
|---|---|---|
/ResultantPolicies | account eq "…" [and device eq "…"] [and class eq "…"], либо только class eq "…" | результирующий набор политики по классу: content, from, layers; по одному классу — набор корня (root/<class>) и наборы учёток, отличающиеся от него |
/FreeNumbers | `kind eq "person | room |
Режим читателя (/Users под токеном человека)
| Запрос | Ответ |
|---|---|
GET /Users | ростер: все, кого читатель вправе держать, с …simple:2.0:Reader на каждой строке (строка клиента: username = uid, login, display_name, groups, attrs, name_only, inactive, …) и на списке (cursor, coversOrg, phones) |
GET /Users?since=N&count= | дельта: строки после курсора; gone у тех, кто ушёл из виду; tooLong — читать ростер заново |
GET /Users?filter=displayName co "текст" / userName eq "…" / emails.value eq " |