В моей дебютной статье мы по шагам проектировали модель разграничения доступа к предметной области, рассматривая в качестве примера выдуманную ECM систему, которая от простой постепенно становилась не очень простой. Мы столкнулись с проблемами, которые не смогли легко и просто решить в рамках той модели, что у нас получилась в результате. В этой статье попытаемся исправить положение.
Чтобы грамотно решить наши вышеозначенные проблемы – вернёмся чуть назад, к самой первой картинке
Текущая схема содержит список доступа для каждого объекта предметной области.
Из теоретической части мы уже примерно поняли, какие паттерны разграничения доступа должна поддерживать наша модель безопасности.
Поэтому будем повышать градус абстракции. Будем в ACL указывать не список субъектов безопасности с их правами, а список моделей доступа, применимых к данному объекту. При этом главенство модели ACL над всеми остальными будем поддерживать соблюдением аксиомы – мы должны всегда иметь возможность доступ к объекту вычислить исключительно на основании его ACL.
Итак, изменяем схему следующим образом
Тут и далее – схема классов, а не схема БД. Вопросами маппинга схемы классов на БД озаботимся позднее (в следующей статье). Белая закрытая стрелочка – это наследование. Открытая стрелочка – это ассоциация
Как вы уже поняли – список доступа к документам выродился в некий иерархический список поддерживаемых объектом SecurityAspect – абстрактных механизмов предоставления доступа. SecurityAspect реализованы нами с помощью паттерна Composite.
Прошу заметить, что я для паттерна Composite не указал промежуточную сущность для связи много ко многим между SecurityAspectComposite и SecurityAspect. В остальных случаях (не касающихся паттерна Composite) я буду такие промежуточные сущности указывать.
Также обращаю внимание на то, что SecurityAspect не ссылаются на Object. Наоборот, Object содержит ссылку на корневой SecurityAspect, который и будет (вместе со своей иерархией) определять доступ к данному объекту.
В дальнейшем корневой SecurityAspect объекта (вместе со своей иерархией) я буду по-старинке обзывать ACL.
Из теоретической части (и из наших требований, изложенных в проблеме 2) мы поняли, что пользователь системы может обладать несколькими наборами привилегий, причём в один момент времени активной должен быть только один набор.
Простой пример – если пользователь системы может работать от своего имени, от имени начальника и от имени совсем большого начальника (типичный сценарий работы секретаря) – бизнес логике системы быстро настанет кирдык, если в каждый конкретный момент не будет понятно от имени кого пользователь совершает то или иное действие в системе.
Отразим всё это на схеме.
Как мы видим, каждый пользователь может иметь набор ассоциированных с ним Principal, которые могут образовывать иерархии (также с помощью паттерна Composite). Для наглядности мы завели конкретные реализации – Principal для орг. структуры организаций.
Кроме того, на диаграмме присутствует и Session, которая, кроме ссылки на пользователя, также ссылается и на тот Principal, от имени которого работает пользователь в данный момент.
Доступ в дальнейшем мы будем предоставлять не пользователям, а Principal’ам. Это позволит легко реализовать сценарии замещения (проблема 2).
Теперь давайте скрестим эти две схемы и реализуем непосредственный доступ к объектам через Principal’s.
Мы создали потомка нашего SecurityAspect с именем DirectAccess, который имеет как список прав по отношению к объекту, так и ссылку на Principal, для которого эти права собственно и доступны.
Обратите внимание, что, в отличии от модели данных в предыдущей статье, в этой модели права не являются атрибутами, а выделены в отдельную сущность Right, которая связана с DirectAccess через DirectAccessRights. Это позволит нам в будущем безболезненно этот набор прав расширять.
Как я обещал ранее, в нашей системе тоже будут роли. Реализуем
Как мы видим – создан новый SecurityAspect с именем Role, который может объединять в себе иерархически другие SecurityAspect’s (т.к. отнаследован от SecurityAspectComposite).
Поскольку роли чаще всего используются для декларативного назначения прав и не будут указываться в ACL объектов (хотя наша модель это и не запрещает) – нам надо обеспечить связь между ролями и Principal’ами. Делаем это с помощью PrincipalSecurityAspects.
Более подробно про использование ролей:
Cамое важное:
Давайте реализуем Multilevel модель безопасности, т.е. раздачу прав на основании какого-нибудь признака объекта. Пусть это будет ObjectKind.
Как видим – объекты стали иметь классифицирующий признак ObjectKind и появился новый наследник от SecurityAspectLeaf (что как бы намекает, что он не может содержать иерархию других SecurityAspect) с именем ObjectKindAccess. Связь между ним и Principal’ом обеспечивается также как и в случае с Role через PrincipalSecurityAspect.
Самое важное:
И напоследок у нас осталась проблема 1 с зависимыми списками доступа.
Напомню суть – объекты, обладая каждый своим списком доступа, участвуя в одном бизнес-процессе, часто должны быть доступны всем участникам этого процесса. Т.е. если какой-то пользователь имеет доступ к объекту А, то он также должен иметь доступ и к объекту Б (обычно с ограниченным набором прав).
Реализуем
Как у нас водится – мы создали нового наследника от SecurityAspectComposite с именем LinkedAccess.
Хитрость в том, что этот SecurityAspect будет «оборачивать» корневой SecurityAspect связанного объекта, таким образом предоставляя доступ всем тем, кто имел доступ к нему, и к текущему объекту. Права же, определённые на LinkedAccess через LinkedAccessRights будут либо ограничивать в правах имеющих доступ к связанному объекту, либо расширять их набор прав (в зависимости от требований бизнес-логики).
В следующей статье будем заниматься маппингом всего этого на БД учитывая обязательное требование из первой статьи
“архитектурные решения, стоящие за решением вышеозначенных проблем абсолютно точно не должны влиять на скорость фильтрации объектов при поисках и должны минимально влиять на скорость совершений операций над объектами и над списками объектов (в том числе, большими).»
Design Patterns for Role-Based Access Control
Patterns and Pattern Diagrams for Access Control
Patterns for Session-Based Access Control
Напомню список проблем, с коротыми мы столкнулись
- Проблема 1 — Зависимые списки доступа
- Проблема 2 — Делегирование полномочий
- Проблема 3 — Предоставление доступа к большому количеству объектов
Небольшое теоретическое отступление
«Там» так же, как и «тут» очень любят изобретать велосипеды. Но «там» за теми, кто любит изобретать велосипеды следят те, кто любит считать деньги. Поэтому вместо изобретения велосипедов «там» занимаются классификацией и стандартизацией.
Касательно разграничения доступа всевозможные модели разграничения доступа классифицируют по двум «параллельным классификациям»
MAC (Mandatory Access Control) — в том случае, если доступ к объектам настраивает администратор декларативно, но не конечный пользователь системы.
DAC (Discretionary Access Control) – в том случае, если доступ к объектам настраивает сам пользователь (к тем объектам, «владельцем» которых он является)
Multilevel – если доступ настраивается по отношению к некоему «уровню доступа», а объекты уже помечаются каким-то признаком, определяющим нужный уровень доступа для работы с этим объектом.
Access Matrix – если доступ настраивается непосредственно между объектом и субъектом безопасности. Частным случаем этой модели является предмет наших страданий, т.е. модель доступа на основании Access Control List (списка доступа). А есть ещё один частный случай – модель доступа на основании Capabilities. Отличаются они тем, что ACL — это список тех, кто имеет права по отношению к какому-то одному объекту, а Capabilities (или C-List) – это список объектов с правами доступа к ним по отношению к какому-то субъекту безопасности. сравнение 1 (англ), сравнение 2 (англ)
Role-Based Access Control (RBAC) – если доступ настраивается по отношению к ролям пользователя, объединяющих возможность выполнения различных функций системы с правами по отношению к объектам безопасности. На эту модель есть стандарт
Attribute-Based Access Control (ABAC) – если доступ настраивается по отношению… нет, не к атрибутам объектов. А по отношению к объектам, обладающим каким-то признаком. Типичный пример разграничения доступа на основании ABAC: менеджер Петров автоматически получает доступ к любым договорам, но только если у них Сумма меньше 100к.
На фоне всего этого ещё болтается такой термин, как Access Control Session, который периодически подмазывают то к RBAC, то к ABAC и который в вольной трактовке означает то, что субъект безопасности может обладать нескольким набором привилегий, но для совершения какой-то определённой операции ему разрешается использовать только один набор, для чего эта операция выполняется в рамках сессии безопасности, с которой оный набор и ассоциирован.
Теперь давайте посмотрим какие же модели безопасности используются для нашей простой ECM системы, занимающейся (напоминаю) обеспечением документооборота организации (ну вы уже поняли, что их там будет не одна).
Итак:
В общем, сборная солянка.
От всего этого у меня только две мысли:
Касательно разграничения доступа всевозможные модели разграничения доступа классифицируют по двум «параллельным классификациям»
- По тому, кто управляет доступом к объектам
- По тому, на основании чего управляют доступом к объектам
По первой классификации модель можно обозвать
MAC (Mandatory Access Control) — в том случае, если доступ к объектам настраивает администратор декларативно, но не конечный пользователь системы.
DAC (Discretionary Access Control) – в том случае, если доступ к объектам настраивает сам пользователь (к тем объектам, «владельцем» которых он является)
По второй классификации модель можно обозвать
Multilevel – если доступ настраивается по отношению к некоему «уровню доступа», а объекты уже помечаются каким-то признаком, определяющим нужный уровень доступа для работы с этим объектом.
Access Matrix – если доступ настраивается непосредственно между объектом и субъектом безопасности. Частным случаем этой модели является предмет наших страданий, т.е. модель доступа на основании Access Control List (списка доступа). А есть ещё один частный случай – модель доступа на основании Capabilities. Отличаются они тем, что ACL — это список тех, кто имеет права по отношению к какому-то одному объекту, а Capabilities (или C-List) – это список объектов с правами доступа к ним по отношению к какому-то субъекту безопасности. сравнение 1 (англ), сравнение 2 (англ)
Role-Based Access Control (RBAC) – если доступ настраивается по отношению к ролям пользователя, объединяющих возможность выполнения различных функций системы с правами по отношению к объектам безопасности. На эту модель есть стандарт
Attribute-Based Access Control (ABAC) – если доступ настраивается по отношению… нет, не к атрибутам объектов. А по отношению к объектам, обладающим каким-то признаком. Типичный пример разграничения доступа на основании ABAC: менеджер Петров автоматически получает доступ к любым договорам, но только если у них Сумма меньше 100к.
На фоне всего этого ещё болтается такой термин, как Access Control Session, который периодически подмазывают то к RBAC, то к ABAC и который в вольной трактовке означает то, что субъект безопасности может обладать нескольким набором привилегий, но для совершения какой-то определённой операции ему разрешается использовать только один набор, для чего эта операция выполняется в рамках сессии безопасности, с которой оный набор и ассоциирован.
Теперь давайте посмотрим какие же модели безопасности используются для нашей простой ECM системы, занимающейся (напоминаю) обеспечением документооборота организации (ну вы уже поняли, что их там будет не одна).
Итак:
- Пользователь может настраивать доступ к документам, особенно если он сам их создаёт. Поэтому, наша модель доступа явно относится к DAC
- Администратор декларативно настраивает доступ к документам (вспомним список доступа по-умолчанию), потому что пользователь НЕ ДОЛЖЕН настраивать доступ сам в 99% сценариев использования (я писал об этом в первой статье). Поэтому, наша модель доступа явно относится и к MAC
- Доступ у нас настраивается на основании списка доступа, поэтому наша модель относится к Access Matrix, в частности к Access Control List
- Из предметной области лезут такие признаки документов как «Гриф доступа», «Конфиденциальность», которые тоже влияют на доступ – в результате наша модель будет относится и к Multilevel. Да и раздача доступа через классифицирующий признак ObjectKind из первой статьи относится к этому же типу
- Ну и конечно, роли. Куда же без них и где же их нет? И в нашей системе тоже будут и поэтому модель безопасности также будет относится и к RBAC
- И не забываем про делегирование полномочий. Потому что этот сценарий требует учёта в нашей модели и Access Control Session
В общем, сборная солянка.
От всего этого у меня только две мысли:
- Архитектор просто обязан сделать всё, чтобы минимизировать количество паттернов разграничения доступа, которые будет поддерживать модель конкретной системы
- Как тут не писать велосипеды, я лично, не понимаю...
Базовая схема
Чтобы грамотно решить наши вышеозначенные проблемы – вернёмся чуть назад, к самой первой картинке
Текущая схема содержит список доступа для каждого объекта предметной области.
Из теоретической части мы уже примерно поняли, какие паттерны разграничения доступа должна поддерживать наша модель безопасности.
Поэтому будем повышать градус абстракции. Будем в ACL указывать не список субъектов безопасности с их правами, а список моделей доступа, применимых к данному объекту. При этом главенство модели ACL над всеми остальными будем поддерживать соблюдением аксиомы – мы должны всегда иметь возможность доступ к объекту вычислить исключительно на основании его ACL.
Итак, изменяем схему следующим образом
Тут и далее – схема классов, а не схема БД. Вопросами маппинга схемы классов на БД озаботимся позднее (в следующей статье). Белая закрытая стрелочка – это наследование. Открытая стрелочка – это ассоциация
Как вы уже поняли – список доступа к документам выродился в некий иерархический список поддерживаемых объектом SecurityAspect – абстрактных механизмов предоставления доступа. SecurityAspect реализованы нами с помощью паттерна Composite.
Прошу заметить, что я для паттерна Composite не указал промежуточную сущность для связи много ко многим между SecurityAspectComposite и SecurityAspect. В остальных случаях (не касающихся паттерна Composite) я буду такие промежуточные сущности указывать.
Также обращаю внимание на то, что SecurityAspect не ссылаются на Object. Наоборот, Object содержит ссылку на корневой SecurityAspect, который и будет (вместе со своей иерархией) определять доступ к данному объекту.
В дальнейшем корневой SecurityAspect объекта (вместе со своей иерархией) я буду по-старинке обзывать ACL.
Пользователи
Из теоретической части (и из наших требований, изложенных в проблеме 2) мы поняли, что пользователь системы может обладать несколькими наборами привилегий, причём в один момент времени активной должен быть только один набор.
Простой пример – если пользователь системы может работать от своего имени, от имени начальника и от имени совсем большого начальника (типичный сценарий работы секретаря) – бизнес логике системы быстро настанет кирдык, если в каждый конкретный момент не будет понятно от имени кого пользователь совершает то или иное действие в системе.
Отразим всё это на схеме.
Как мы видим, каждый пользователь может иметь набор ассоциированных с ним Principal, которые могут образовывать иерархии (также с помощью паттерна Composite). Для наглядности мы завели конкретные реализации – Principal для орг. структуры организаций.
Кроме того, на диаграмме присутствует и Session, которая, кроме ссылки на пользователя, также ссылается и на тот Principal, от имени которого работает пользователь в данный момент.
Доступ в дальнейшем мы будем предоставлять не пользователям, а Principal’ам. Это позволит легко реализовать сценарии замещения (проблема 2).
Непосредственный доступ к объектам
Теперь давайте скрестим эти две схемы и реализуем непосредственный доступ к объектам через Principal’s.
Мы создали потомка нашего SecurityAspect с именем DirectAccess, который имеет как список прав по отношению к объекту, так и ссылку на Principal, для которого эти права собственно и доступны.
Обратите внимание, что, в отличии от модели данных в предыдущей статье, в этой модели права не являются атрибутами, а выделены в отдельную сущность Right, которая связана с DirectAccess через DirectAccessRights. Это позволит нам в будущем безболезненно этот набор прав расширять.
Роли
Как я обещал ранее, в нашей системе тоже будут роли. Реализуем
Как мы видим – создан новый SecurityAspect с именем Role, который может объединять в себе иерархически другие SecurityAspect’s (т.к. отнаследован от SecurityAspectComposite).
Поскольку роли чаще всего используются для декларативного назначения прав и не будут указываться в ACL объектов (хотя наша модель это и не запрещает) – нам надо обеспечить связь между ролями и Principal’ами. Делаем это с помощью PrincipalSecurityAspects.
Более подробно про использование ролей:
- Они могут использоваться как для предоставления доступа к функциям системы, так и для предоставления доступа к объектам системы
- В первом случае в нашей модели будут просто заведены нужные роли с нужным набором прав, не равным тем правам, которые будут использоваться для доступа к объектам и эти роли будут прописаны для Pricipal’ов в PrincipalSecurityAspects
- Во втором случае в нашей модели будут также заведены роли, также прописаны Principal’ам в PrincipalSecurityAspects и дополнительно – в ACL тех объектов, для которых эти роли применимы. Набор прав, используемые в ролях, в этом случае может быть равен тому, который используется в DirectAccess
Cамое важное:
- В классическом RBAC в сущности Role должна быть связь между ней и Object через RoleRights
- Поскольку у нас не RBAC, а ACL главенствует – эта связь отсутствует и поэтому в случае необходимости предоставлять доступ к объектам через роли – они должны быть прописаны в ACL соответствующих объектов
Доступ по-умолчанию
Давайте реализуем Multilevel модель безопасности, т.е. раздачу прав на основании какого-нибудь признака объекта. Пусть это будет ObjectKind.
Как видим – объекты стали иметь классифицирующий признак ObjectKind и появился новый наследник от SecurityAspectLeaf (что как бы намекает, что он не может содержать иерархию других SecurityAspect) с именем ObjectKindAccess. Связь между ним и Principal’ом обеспечивается также как и в случае с Role через PrincipalSecurityAspect.
Самое важное:
- В классическом Multilevel сущность Object для раздачи к нему прав должен быть помечен классифицирующим признаком и всё
- Поскольку у нас ACL первичен, для тех объектов, для которых должна работать модель Multilevel – в ACL должен быть прописан соответствующий SecurityAspect
Зависимые списки доступа
И напоследок у нас осталась проблема 1 с зависимыми списками доступа.
Напомню суть – объекты, обладая каждый своим списком доступа, участвуя в одном бизнес-процессе, часто должны быть доступны всем участникам этого процесса. Т.е. если какой-то пользователь имеет доступ к объекту А, то он также должен иметь доступ и к объекту Б (обычно с ограниченным набором прав).
Реализуем
Как у нас водится – мы создали нового наследника от SecurityAspectComposite с именем LinkedAccess.
Хитрость в том, что этот SecurityAspect будет «оборачивать» корневой SecurityAspect связанного объекта, таким образом предоставляя доступ всем тем, кто имел доступ к нему, и к текущему объекту. Права же, определённые на LinkedAccess через LinkedAccessRights будут либо ограничивать в правах имеющих доступ к связанному объекту, либо расширять их набор прав (в зависимости от требований бизнес-логики).
Что дальше
В следующей статье будем заниматься маппингом всего этого на БД учитывая обязательное требование из первой статьи
“архитектурные решения, стоящие за решением вышеозначенных проблем абсолютно точно не должны влиять на скорость фильтрации объектов при поисках и должны минимально влиять на скорость совершений операций над объектами и над списками объектов (в том числе, большими).»
Что почитать
Design Patterns for Role-Based Access Control
Patterns and Pattern Diagrams for Access Control
Patterns for Session-Based Access Control