Недавно мы реализовали систему доступа в корпоративном мессенджере компании и хотели бы поделиться с теми, у кого мало опыта в решении подобных задач, своими наработками в небольшом цикле статей. Для удобства изложения мы разбили материал на две части: в данной статье будут подробно описаны все составляющие системы, а объяснению их взаимодействия и принципов работы мы посвятим отдельный пост в недалеком будущем.
Backend для мессенджера написан на Go, поэтому и примеры будут на этом языке. Не желая изобретать велосипед, мы решили взять за основу XACML — стандарт для ABAC (Attribute-Based Access Control) — и максимально упростили его, чтобы он подходил для нашей задачи. Хотим отметить, что мы не ставили перед собой цель написать собственную реализацию XACML. Он был взят как пример работающей системы, из которого мы могли бы извлечь нужный для нас опыт.
Для знакомства с XACML и ABAC есть отличные статьи:
> Знакомство с XACML — стандартом для Attribute-Based Access Control
> Подходы к контролю доступа: RBAC vs. ABAC
Сразу расскажем об интерфейсе AttributeCalculater, так как он будет встречаться далее. По сути, он состоит из трех других интерфейсов, но для краткости мы ограничимся тем, что просто запишем все его методы. Его должны реализовать все объекты модели приложения, которые взаимодействуют с системой доступа.
В системе используются два основных типа объектов: Правила и Политики. Для нашей задачи этого достаточно, поэтому группы политик мы не стали использовать за ненадобностью.
Правило — это самый простой объект в системе, который используется для описания бизнес-правил. Вот его структура:
Метод calculate вычисляет правило, то есть возвращает значение, которое говорит, может запрос быть выполненным или нет, или сообщает о возникшей ошибке. Для этого в метод передается контекст, в котором содержится вся необходимая информация для вычисления.
Контекст состоит из объекта (object) — сущности, которая реализует интерфейс AttributeCalculater и с которой система доступа выполняет какие-то действия, субъекта (subject) — сущности, которая так же поддерживает интерфейс AttributeCalculater и обычно является пользователем, желающим выполнить определенное действие в приложении. Цель (target) является enum'ом, в котором перечислены все возможные действия, поддерживающиеся системой доступа. Например: добавить пользователя в переписку, написать сообщение, назначить админа переписки и т.д.
Name (имя) правила нужно прежде всего для человека, который с ним работает — на сам процесс вычисления оно никак не влияет.
Effect (эффект) показывает, как будет обрабатываться результат вычисления условия. Эффект может быть разрешающим (permitEffect) или запрещающим (denyEffect). Скажем, если результат вычисления условия — true, а эффект задан как permitEffect, то результат вычисления правила также будет true. Если же эффект прописан как denyEffect, то результатом правила будет false.
Condition (условие) — самая главная часть правила, в которой, собственно, описывается и высчитывается условие для него.
Метод calculate вычисляет условие. Он похож на аналогичный метод у правила, только возвращаемые значения у него другие. Условие может быть верно, неверно или же сообщать об ошибке.
Operator (оператор) отвечает за то, как сравниваются два операнда. Принимает следующие значения:
Как видно из структуры, условие может быть вычислено только для двух операндов, то есть в одном правиле не предполагается рассмотрение сложных use case'ов, которые возникают при работе с системой доступа. Для этого используются комбинации правил.
Тип данных операндов — это Attribute (атрибут). В нем находится информация вычисления условий.
Метод getValue возвращает значение атрибута. Возвращается оно в виде объекта, у которого реализован интерфейс AttributeCalculater.
NameObject (имя объекта), у которого при вычислении атрибута берется значение из поля Field. Сам же объект находится в поле Object.
Политики используются для описания бизнес-правил с одним или несколькими правилами.
Name (имя) у политики, как и у правила, нужно только для человека, который с ней работает.
Targer (цель) используется для поиска политик. Для простоты в нашей системе у каждой цели своя политика.
Rules (правила) — это набор простых правил, которые дополняя друг друга могут описывать сложные бизнес-правила.
CombineAlgorithm (алгоритм комбинирования) правил указывает на то, как обрабатывать результаты вычисления правил политики. В XACML эти алгоритмы могут быть достаточно сложными, но в нашем случае все эти изыски не нужны. Поэтому у нас пока всего два простых алгоритма permitIfAllPermitted (разрешить, если все разрешили) и permitIfOnePermitted (разрешить, если один разрешил). Например, если стоит алгоритм permitIfAllPermitted, то результат вычисления политики будет положительным только при том условии, что все правила в этой политике также имели положительный результат.
Вот основные части, из которых состоит наша система доступа. В следующей статье мы подробно рассмотрим, как это все работает.
Backend для мессенджера написан на Go, поэтому и примеры будут на этом языке. Не желая изобретать велосипед, мы решили взять за основу XACML — стандарт для ABAC (Attribute-Based Access Control) — и максимально упростили его, чтобы он подходил для нашей задачи. Хотим отметить, что мы не ставили перед собой цель написать собственную реализацию XACML. Он был взят как пример работающей системы, из которого мы могли бы извлечь нужный для нас опыт.
Для знакомства с XACML и ABAC есть отличные статьи:
> Знакомство с XACML — стандартом для Attribute-Based Access Control
> Подходы к контролю доступа: RBAC vs. ABAC
Базовые объекты системы и интерфейс AttributeCalculater
Сразу расскажем об интерфейсе AttributeCalculater, так как он будет встречаться далее. По сути, он состоит из трех других интерфейсов, но для краткости мы ограничимся тем, что просто запишем все его методы. Его должны реализовать все объекты модели приложения, которые взаимодействуют с системой доступа.
type AttributeCalculater interface {
Counter() (AttributeCalculater, error)
Equally(Getter) bool
Belong(Getter) bool
GetType() string
GetValue() (AttributeCalculater, error)
GetValueField(string) (AttributeCalculater, error)
GetInt() (int, error)
GetBool() (bool, error)
GetString() (string, error)
}
В системе используются два основных типа объектов: Правила и Политики. Для нашей задачи этого достаточно, поэтому группы политик мы не стали использовать за ненадобностью.
Правило (rule)
Правило — это самый простой объект в системе, который используется для описания бизнес-правил. Вот его структура:
type rule struct {
Name string
Condition condition
Effect ruleEffect
}
func (r *rule) calculate(cntx *Context) calculateResult {}
Метод calculate вычисляет правило, то есть возвращает значение, которое говорит, может запрос быть выполненным или нет, или сообщает о возникшей ошибке. Для этого в метод передается контекст, в котором содержится вся необходимая информация для вычисления.
type Context struct {
Object AttributeCalculater
Subject AttributeCalculater
Target Action
}
Контекст состоит из объекта (object) — сущности, которая реализует интерфейс AttributeCalculater и с которой система доступа выполняет какие-то действия, субъекта (subject) — сущности, которая так же поддерживает интерфейс AttributeCalculater и обычно является пользователем, желающим выполнить определенное действие в приложении. Цель (target) является enum'ом, в котором перечислены все возможные действия, поддерживающиеся системой доступа. Например: добавить пользователя в переписку, написать сообщение, назначить админа переписки и т.д.
Name (имя) правила нужно прежде всего для человека, который с ним работает — на сам процесс вычисления оно никак не влияет.
Effect (эффект) показывает, как будет обрабатываться результат вычисления условия. Эффект может быть разрешающим (permitEffect) или запрещающим (denyEffect). Скажем, если результат вычисления условия — true, а эффект задан как permitEffect, то результат вычисления правила также будет true. Если же эффект прописан как denyEffect, то результатом правила будет false.
Condition (условие) — самая главная часть правила, в которой, собственно, описывается и высчитывается условие для него.
type condition struct {
FirstOperand Attribute
SecondOperand Attribute
Operator conditionOperator
}
func (c *condition) calculate(cntx *Context) (bool, error) {}
Метод calculate вычисляет условие. Он похож на аналогичный метод у правила, только возвращаемые значения у него другие. Условие может быть верно, неверно или же сообщать об ошибке.
Operator (оператор) отвечает за то, как сравниваются два операнда. Принимает следующие значения:
- equally - проверяет, равны ли операнды.
- notEqually — проверяет, не равны ли операнды.
- belong — проверяет, есть ли между операндами какое-то отношение. Конкретная логика зависит от реализации интерфейса AttributeCalculater, который должны реализовать объекты, работающие с системой доступа. Подробнее об этом расскажем ниже.
- notBelong — противоположность belong.
Как видно из структуры, условие может быть вычислено только для двух операндов, то есть в одном правиле не предполагается рассмотрение сложных use case'ов, которые возникают при работе с системой доступа. Для этого используются комбинации правил.
Тип данных операндов — это Attribute (атрибут). В нем находится информация вычисления условий.
type Attribute struct {
NameObject string
Field string
Type TypeAttribute
Object AttributeCalculater
}
func (a *Attribute) getValue(c *Context) (AttributeCalculater, error) {}
Метод getValue возвращает значение атрибута. Возвращается оно в виде объекта, у которого реализован интерфейс AttributeCalculater.
NameObject (имя объекта), у которого при вычислении атрибута берется значение из поля Field. Сам же объект находится в поле Object.
Политика (politic)
Политики используются для описания бизнес-правил с одним или несколькими правилами.
type politic struct {
Name string
Target Action
Rules []rule
CombineAlgorithm combineAlgorithm
}
func (p *politic) calculate(cntx *Context) calculateResult {}
Name (имя) у политики, как и у правила, нужно только для человека, который с ней работает.
Targer (цель) используется для поиска политик. Для простоты в нашей системе у каждой цели своя политика.
Rules (правила) — это набор простых правил, которые дополняя друг друга могут описывать сложные бизнес-правила.
CombineAlgorithm (алгоритм комбинирования) правил указывает на то, как обрабатывать результаты вычисления правил политики. В XACML эти алгоритмы могут быть достаточно сложными, но в нашем случае все эти изыски не нужны. Поэтому у нас пока всего два простых алгоритма permitIfAllPermitted (разрешить, если все разрешили) и permitIfOnePermitted (разрешить, если один разрешил). Например, если стоит алгоритм permitIfAllPermitted, то результат вычисления политики будет положительным только при том условии, что все правила в этой политике также имели положительный результат.
Вот основные части, из которых состоит наша система доступа. В следующей статье мы подробно рассмотрим, как это все работает.
Поделиться с друзьями