Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Глава 44. Контекст определяет доступ

В предыдущих главах мы последовательно прошли несколько уровней.

Сначала появился объект.

Затем отношения вокруг объекта.

Затем из множества отношений и других фактов мы выделили те, которые имеют значение для конкретного запроса.

Так появился контекст.

Но теперь возникает главный вопрос:

Что происходит с контекстом дальше?

Сам по себе контекст ещё ничего не разрешает.

Он только содержит информацию, необходимую для применения правил.

Поэтому следующая часть цепочки выглядит так:

Объект
   ↓
Отношения
   ↓
Релевантные факты
   ↓
Контекст
   ↓
Правила
   ↓
Эффективное разрешение
   ↓
Решение о доступе

Именно здесь становится окончательно понятно, зачем вообще нужен контекст.

Он связывает предметную модель с решением о допустимости действия.

44.1 Контекст не принимает решение сам

Предположим, у нас есть:

User A
Document D
Action = READ

И контекст сообщает:

User A
→ member of
→ Project P

Document D
→ belongs to
→ Project P

Можно ли на этом основании разрешить чтение?

Контекст сам этого не знает.

Он содержит факты.

Правило может сказать:

если пользователь является участником проекта,
к которому относится документ,
то участник может читать документ.

Тогда возникает:

Context
   ↓
Rule
   ↓
READ

Но другое правило могло бы сказать:

участник проекта может изменять документ
только если ему назначена роль Editor.

Тогда тот же контекст дал бы другой результат.

Следовательно:

контекст не определяет разрешение без правил.

Он предоставляет входные данные для правил.

44.2 Одни и те же отношения могут давать разные права

Это важное свойство.

Пусть:

User A → member of → Project P
Document D → belongs to → Project P

Эти факты не меняются.

Но действия различаются:

READ
UPDATE
APPROVE
CLOSE

Правила могут определить:

READ     → разрешено
UPDATE   → разрешено
APPROVE  → запрещено
CLOSE    → запрещено

Поэтому нельзя считать, что наличие отношения означает наличие одного универсального права.

Отношение даёт основание.

Правило определяет, для каких действий это основание действительно.

Получается:

Relation
   +
Rule
   +
Action
   ↓
Effective permission

44.3 Одно отношение может участвовать в нескольких правилах

Например:

User A → owner of → Document D

Это отношение может использоваться для разных действий.

Одно правило может разрешать владельцу:

READ

другое:

UPDATE

третье:

CLOSE

Но это не означает, что отношение owner само содержит эти разрешения.

Оно остаётся одним фактом:

Owner(User A, Document D)

А набор разрешений возникает из правил.

Это позволяет изменить модель без изменения самого предметного факта.

Например, если бизнес-правило изменилось и владелец больше не может самостоятельно закрывать объект, отношение владельца остаётся тем же.

Меняется правило.

44.4 Контекст может приводить к разным результатам

Один и тот же объект может находиться в разных контекстах для разных субъектов.

Например:

Document D

Для пользователя A:

owner

Для пользователя B:

project member

Для пользователя C:

published to group

Для пользователя D:

delegated access

Поэтому вопрос:

Какие права имеет Document D?

не является полным.

Нужно спрашивать:

Какие права имеет Subject S
над Object O
для Action A
в Context C?

Именно контекст делает это решение конкретным.

44.5 Контекст может ограничивать уже найденное основание

Не все правила работают по принципу:

если факт существует → разрешить.

Иногда отношение является необходимым, но недостаточным условием.

Например:

User A → member of → Project P

может быть необходимо для чтения.

Но документ:

Document D → state = Confidential

может требовать дополнительного основания.

Тогда правило имеет форму:

Project membership
AND
Confidential access role

В другом случае:

Project membership
AND
Document state = Released

Таким образом, контекст может содержать одновременно:

  • основания доступа;

  • ограничения;

  • состояние объекта;

  • область действия;

  • дополнительные условия.

Правило определяет, как они комбинируются.

44.6 Контекст не обязан содержать готовый ответ

Это принципиально для архитектуры.

Можно представить контекст:

Subject = A
Action = APPROVE
Object = D

Relations:
  member(Project P)
  role(Reviewer)

Object state:
  Review

Publication:
  Project P

Это ещё не:

ALLOW

и не:

DENY

Это вход модели.

После применения правил может получиться:

Effective permission = APPROVE

а затем:

ALLOW

Или при другом состоянии объекта:

Effective permission = none

и:

DENY

Так сохраняется различие между фактами и выводами.

44.7 Эффективное разрешение — промежуточный результат

В предыдущих главах мы уже различили назначенное и эффективное разрешение.

Теперь видно, где появляется второе.

Например, исходные факты:

User A → role Reviewer → Project P
User A → member of Project P
Document D → belongs to Project P

могут привести к:

Effective permission:
APPROVE

Но это ещё не окончательное решение.

Нужно проверить конкретное действие:

Requested action = APPROVE

Если оно входит в эффективное разрешение:

APPROVE ∈ EffectivePermissions

получаем:

ALLOW

Если нет:

APPROVE ∉ EffectivePermissions

получаем:

DENY

Поэтому цепочка остаётся:

Facts
   ↓
Context
   ↓
Rules
   ↓
Effective permission
   ↓
Decision

44.8 Почему полезно отделять разрешение от решения

На первый взгляд можно было бы сразу вычислять:

ALLOW / DENY

Но промежуточный слой имеет важное значение.

Он позволяет понять:

почему право возникло;

и:

какие права вообще действуют в данном контексте.

Например:

User A
Project P
Role Reviewer

Effective permissions:
READ
APPROVE

Тогда проверка:

READ

и:

APPROVE

использует один и тот же подготовленный результат.

Но:

CLOSE

может отсутствовать.

Такой подход особенно полезен, когда один субъект выполняет много действий над одним объектом.

44.9 Несколько оснований могут привести к одному разрешению

Предположим:

User A → owner of → Document D

и одновременно:

User A → member of → Project P
Document D → belongs to → Project P

Оба пути могут давать:

READ

Тогда эффективный результат всё равно:

READ

Не нужно создавать два разных READ только потому, что у него две причины.

Причины остаются частью модели.

Результат может быть одним.

Это позволяет отделить:

why

от:

what

То есть:

Основания → почему право возможно
Permission → какое действие разрешено
Decision → разрешено ли конкретное действие

44.10 Разные основания могут давать разные права

В другом случае:

owner

может давать:

READ
UPDATE
CLOSE

а:

project membership

только:

READ

Тогда объединение результатов зависит от правил модели.

Получаем:

Owner
   └── READ, UPDATE, CLOSE

Project member
   └── READ

И эффективный результат может быть:

READ, UPDATE, CLOSE

Но это не универсальный закон.

В другой модели одно отношение может ограничивать другое.

Например:

Project member → UPDATE

но:

Document state = Locked

может запрещать UPDATE.

Поэтому нельзя заранее предполагать, что все права просто складываются.

Способ объединения и ограничения определяется правилами.

44.11 Контекст определяет применимость правила

Правило существует не в вакууме.

Например:

Reviewer may approve a document

нельзя применить только потому, что пользователь где-то является Reviewer.

Нужно определить:

Reviewer where?
Reviewer for what?
Reviewer over which object?
Reviewer for which action?

Именно здесь появляется область отношения.

Например:

User A
→ Reviewer
→ Project P

может применяться к:

Document D
→ belongs to Project P

но не к:

Document E
→ belongs to Project Q

Таким образом, контекст определяет не только наличие отношения, но и его применимость к конкретному объекту.

44.12 Правила могут требовать пересечения нескольких условий

Рассмотрим:

User A
→ Reviewer
→ Project P

и:

Document D
→ Project P
→ state = Review

Правило может требовать:

Reviewer
AND
same Project
AND
state = Review

Только после выполнения всех условий возникает:

APPROVE

Здесь хорошо видно различие между объединением и пересечением.

Разные независимые основания могут дать дополнительные права.

Но отдельное правило может требовать одновременного выполнения нескольких условий.

Поэтому модель доступа нельзя свести к одной операции над наборами permission.

Сначала нужно сохранить семантику отношений.

44.13 Ограничение может действовать после получения основания

Рассмотрим:

User A → owner of → Document D

и:

Document D → state = Archived

Правило может говорить:

owner → UPDATE

но другое правило:

Archived → UPDATE forbidden

Тогда одного основания недостаточно.

Важно, что это не означает:

owner relation was false

Отношение остаётся истинным.

Просто в текущем контексте его действие ограничено состоянием объекта.

Это ещё одна причина не смешивать:

fact
relation
permission
constraint
decision

44.14 Запрет и отсутствие разрешения — разные вещи

Если пользователь не может выполнить действие, это может означать две разные ситуации.

Первая:

Permission отсутствует.

Вторая:

Permission существует,
но конкретное условие запрещает действие.

Например:

User A → Reviewer

даёт:

APPROVE

но:

Document D → state = Archived

делает APPROVE недопустимым.

Это отличается от ситуации, когда пользователь вообще не является Reviewer.

Поэтому модель должна явно определять семантику ограничений и запретов.

Не существует универсального правила, согласно которому любой DENY автоматически сильнее любого ALLOW.

Это часть конкретной модели доступа.

44.15 Контекст может быть различным при одинаковом результате

Интересна и обратная ситуация.

Для пользователя A:

owner

Для пользователя B:

project member

Для пользователя C:

publication

Все трое могут получить:

READ

Результат одинаков.

Но контексты различны.

Это означает, что:

same permission
≠
same reason

Именно поэтому полезно сохранять отношения и основания отдельно от эффективного разрешения.

Если сохранить только:

User A → READ → Document D

то исчезает информация о том, почему это право возникло.

44.16 Изменение контекста меняет результат без изменения permission-модели

Предположим, правила не менялись.

Роль не менялась.

Но документ перешёл:

Draft → Released

или пользователь:

removed from Project P

Контекст изменился.

Значит, измениться может и эффективное разрешение.

Это показывает важную особенность модели:

правила могут оставаться неизменными, пока результат доступа меняется вслед за изменением исходных фактов.

Именно поэтому security projections должны обновляться при изменении отношений и состояния, если они используются для вычисления эффективных разрешений.

44.17 Изменение правил — другой тип изменения

Теперь рассмотрим другой случай.

Исходные факты те же:

User A → Reviewer
Document D → Review

Но правило изменилось.

Было:

Reviewer may APPROVE.

Стало:

Reviewer may APPROVE
only if assigned as lead reviewer.

Теперь исходные факты могут оказаться недостаточными.

Изменился не контекст.

Изменились правила его интерпретации.

Поэтому модель безопасности должна различать:

изменение фактов

и:

изменение правил.

Оба события могут изменить эффективные разрешения, но механизм их распространения может быть различным.

44.18 Эффективное разрешение является производным фактом

Теперь можно точно определить его место.

Исходными фактами могут быть:

User A → member of Project P
User A → Reviewer in Project P
Document D → belongs to Project P
Document D → state = Review

Производным фактом становится:

User A
→ effective permission APPROVE
→ in context of Project P

Он получен из других данных.

Поэтому его можно:

  • вычислять;

  • материализовать;

  • обновлять;

  • пересчитывать;

  • проверять относительно исходных фактов.

Но он не должен становиться независимым источником истины.

44.19 Правило превращает контекст в эффективное разрешение

Теперь можно записать основную функцию:

EffectivePermission =
    Rules(Context(Subject, Action, Object))

В более общем виде:

Context =
    RelevantFacts(Subject, Action, Object)

EffectivePermission =
    Rules(Context)

А затем:

Decision =
    Check(EffectivePermission, Action)

Это не означает, что реальная система обязана реализовывать именно такие функции буквально.

Это концептуальная модель.

Она показывает разделение ответственности:

RelevantFacts

определяет, что важно.

Context

собирает это состояние.

Rules

интерпретируют его.

EffectivePermission

является результатом.

Decision

отвечает на конкретный запрос.

44.20 В реальной системе контекст и разрешение могут быть распределены по слоям

В физической реализации эти элементы необязательно находятся рядом.

Например:

Источник фактов
        ↓
Проекции
        ↓
Эффективные отношения
        ↓
Эффективные разрешения
        ↓
Проверка объекта
        ↓
Ограничение физических данных

При этом никакая одна таблица не обязана называться Context.

Контекст существует как смысловая конструкция, собранная из нескольких представлений модели.

Это позволяет разделить предметную модель и техническую реализацию.

44.21 Доступ определяется контекстом, но не исчерпывается им

Здесь важно сделать ещё одно различие.

Даже если:

Can(User A, READ, Document D)

получает значение true, это ещё не означает, что пользователь получит любые физические данные, связанные с документом.

Ранее мы уже различили:

Object authorization

и:

Data enforcement

Контекст участвует в авторизации объекта.

Но физические данные могут иметь дополнительные границы.

Поэтому цепочка продолжается:

Context
   ↓
Effective permission
   ↓
Object authorization
   ↓
Data enforcement
   ↓
Physical data

Контекст не отменяет остальные уровни безопасности.

44.22 Решение о доступе всегда относится к конкретному действию

В конечном счёте система отвечает не на вопрос:

Does User A have access to Document D?

Это слишком расплывчатый вопрос.

Нужно спросить:

Can(User A, READ, Document D)?

или:

Can(User A, UPDATE, Document D)?

или:

Can(User A, APPROVE, Document D)?

Один и тот же контекст может привести к разным результатам для разных действий.

Поэтому универсальное свойство:

User A has access to Document D

часто скрывает слишком много информации.

Более точная модель:

Subject
+
Action
+
Object
+
Context
→
Decision

44.23 Доступ становится функцией контекста

Теперь всю модель можно выразить компактно:

Can(S, A, O) =
    Rules(Context(S, A, O))

Где:

Context(S, A, O)

строится из релевантных фактов и отношений.

Получается:

Facts
   ↓
Context(S, A, O)
   ↓
Rules
   ↓
Can(S, A, O)

Это и есть центральный переход от старой модели:

User → Role → Permission

к более общей:

Subject
   +
Action
   +
Object
   +
Context
   ↓
Decision

Роль и permission никуда не исчезают.

Они становятся частью более широкой модели.

44.24 Контекст не усложняет модель ради самой сложности

На этом этапе может показаться, что мы просто добавили ещё один термин.

Но контекст нужен не для усложнения.

Он позволяет не смешивать разные вопросы.

Без него легко сказать:

User A has READ.

Но непонятно:

READ чего?
Где?
На каком основании?
В каком состоянии?
На какой срок?
Через какое отношение?
При каких условиях?

Контекст собирает именно те ответы, которые нужны для конкретного решения.

Он не добавляет произвольную сложность.

Он делает уже существующую сложность явной.

44.25 Главный вывод

Теперь основная цепочка книги практически замкнулась.

Мы начали с объекта:

Object

У объекта есть предметная семантика и возможные отношения:

Object
   ↓
Possible relationships

Фактические отношения соединяют объект с субъектами и другими объектами:

Actual relationships

Из них для конкретного запроса выбираются релевантные факты:

Relevant facts

Они формируют контекст:

Context

Правила интерпретируют контекст:

Context
   ↓
Rules

и дают эффективное разрешение:

Effective permission

После чего проверяется конкретное действие:

Can(Subject, Action, Object)?

И только после этого результат должен быть физически обеспечен на уровне данных.

Полная цепочка:

Object
   ↓
Relationships
   ↓
Relevant facts
   ↓
Context
   ↓
Rules
   ↓
Effective permission
   ↓
Access decision
   ↓
Data enforcement

Каждый уровень отвечает на свой вопрос.

Объект — что является предметом действия?

Отношение — как этот объект связан с другими сущностями?

Факт — что сейчас известно о системе?

Контекст — какие из этих фактов имеют значение для данного решения?

Правило — как интерпретировать эти факты?

Эффективное разрешение — какое право получилось?

Решение — разрешено ли конкретное действие?

Data enforcement — какие физические данные действительно могут быть затронуты?

Главный принцип можно сформулировать коротко:

доступ определяется не свойством пользователя и не свойством объекта. Он является результатом применения правил к контексту конкретного действия над конкретным объектом.

И именно поэтому контекст становится не дополнительным атрибутом системы безопасности, а связующим звеном между предметной моделью и механизмом доступа.

В следующей, последней главе книги останется сделать последний шаг: показать, что после этого доступ перестаёт быть внешней функцией над данными и становится частью самой архитектуры данных.