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

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—
/Serversserver…simple:2.0:Serverоткрытый
/Servicesservice…simple:2.0:Serviceоткрытый (secure_access.gateway, …)
/Sitessite…simple:2.0:Sitedc, office, geo, gateway_group
/Policiespolicy…simple:2.0:Policyполитики установки по одной на вид: credentials, sessions, guests, leavers, reviews, terms, app_links, app_passwords, username_retention, telephony, dialplan, legs, photos, branding; шаблоны quota; профили secure_access.*
/AddressListsaddress_list…simple:2.0:AddressList—
/Authzauthz…simple:2.0:Authzgrants (каталог прав серверной роли, catalogue:<role>), role, assignment (user:<uid>, group:<gid>)
/Legsleg…simple:2.0:Legsip-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 — раньше, чем читатель отвалится по своему таймауту. Читателю положено ходить раз в минуту с разбросом и удваивать паузу после отказа.

Вычисляемые ресурсы (только чтение)​

РесурсФильтрОтвет
/ResultantPoliciesaccount eq "…" [and device eq "…"] [and class eq "…"], либо только class eq "…"результирующий набор политики по классу: content, from, layers; по одному классу — набор корня (root/<class>) и наборы учёток, отличающиеся от него
/FreeNumbers`kind eq "personroom

Режим читателя (/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 "…"поиск людей по книге читателя; truncated
GET /Users/{id}одна строка, 404 вне книги
GET /Users/{id}/photoфото (ETag = SHA-256)

Поток изменений — GET /v1/events каталога (hello {groups, contacts, directory}, directory.changed {cursor}).

Регистрация расширения платформы​

PUT /control/schema/extensions/{platform} с телом {name, classes: [{Class, Types}], attrs: [ObjectDef…]} — координатор регистрирует расширение целиком при включении платформы (shared/dirschema.ExtensionByPlatform); сервисы схему не регистрируют.

Что где лежит​

ДанныеРесурсКто пишет
политики установки (вход, сессии, гости, увольняющиеся, телефония, план набора, пароли приложений, фото, брендинг…)/Policies по typeконсоль/координатор
план нумерации, основной номер/Policies type eq "telephony" (numbering, main_number)координатор
план набора/Policies type eq "dialplan" (plan, ETag)координатор; читает messaging
квоты/Policies type eq "quota" (шаблоны, shared_mailboxes), /ResultantPolicies?filter=class eq "quota"консоль; читают mail, messaging, drive
роли и назначения/Authzконсоль, координатор; читают все через shared/auth.RBACPuller
адресные списки/AddressLists (visible_to)консоль
устройства комнат/Legs (credentials сверяется каталогом: новая запись выдаётся, помеченная removed снимается)координатор; MCU читает /v1/legs/feed
сессии туннелейу координатора (ушли из каталога)—