Search
Write a publication
Pull to refresh
7
0
Юрий Скалецкий @Yenox

Пользователь

Send message

OBAC, несомненно, велосипед по сравнению с Сasbin, которая по сути, сейчас стандарт де-факто для атрибутированного контроля доступа в опенсорсе.

Имеет ли смысл решать ту же задачу по-другому и делать генератор эффективных полномочий или на Сasbin можно сделать все то же самое и даже лучше - это хороший вопрос.

Точнее даже три вопроса:

  • Производительность назначения прав ACL

  • Производительность проверки эффективных полномочий

  • Удобство использования

Насчет померять производительность - я планирую сделать бенчмарк OBAC-а, на каком-нибудь не самом тривиальном случае, навроде такого:

  • 5 уровней в иерархии объектов

  • 5 типов проверяемых полномочий

  • 5 записей ACL на каждый уровень, с назначением доступа пользователям и группам

  • запретительные и разрешительные полномочия. Тут не знаю, как будет правильно, но как идея, для каждого из 5 типов полномочия в цепочке наследования должны попадаться

    • 1 назначение через юзера (allow)

    • 1 назначение через группу (allow)

    • 1 назначение через юзера (deny)

    • 1 назначение через группу (deny)

  • кол-во объектов значимое, например по 10000 в узле нижнего уровня, на каждом уровне по 2 sibling-a (то есть узлов 2/4/8/16 узлов на уровнях 1-4 и 160тысяч объектов нижнего уровня)

  • 10 000 пользователей и 50 групп по 500 пользователей в каждой

и собственно предмет исследования - оконная функция (сортировка+пейджинг) по узлам нижнего уровня.

В случае OBAC очевидно, что скорость сортировки и пейджинга будет эквивалентна одному дополнительному джоину (см мой пример выше), основные ресурсы будут тратиться в момент заполнения ACL, вычисления и сохранения эффективных полномочий.

В случае Casbin/PERM, попробую применить ваши методики.
Самому интересно, что получится.

Мы для себя сделали вывод, что применять Casbin для защиты многих тысяч сущностей, которые создаются в ходе работы системы, не очень себе идея - как раз потому, что нет ясного подхода по работе с эффективными полномочиями. То есть декларативный подход и PERM прекрасны для случая, когда знаешь, какие сущности надо защитить (и как они будут связаны), еще в ходе разработки, а не на момент эксплуатации.

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

В результате была написана библиотека Redberries OBAC (https://github.com/redberriespro/Redb.OBAC), суть которой - раздавать права на иерархические структуры объектов и вычислять для каждого объекта иерархии эффективные полномочия. Посчитанные полномочия можно запросить у библиотеки, а можно и принять в прикладной код специальным ресивером и положить например в БД.

В результате, получение списков из БД с одновременным применением проверки доступа выглядит как-то так:

 var docs = from d in ctx.Documents
 join p in ctx.EffectivePermissions
   on d.Id equals p.ObjectId
 where
   p.UserId == userId && p.PermissionId == PERM_READ
 select d;


Пример на C# и Entity Framework, вот тут весь он: https://github.com/redberriespro/Redb.OBAC/blob/main/Examples/HelloObacEf/Program.cs

Спасибо за перевод.


В разделах "что гуглить" мне лично не хватает оригинальных названий терминов. Каналы — это channels? Глупые компоненты — silly? dumb? stupid? Нестандартные компоненты — non-standard? custom?


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

Есть некоторое пересечение с аугментацией — расширении обучающего датасета на задачах класса Machine Learning. Тоже берется небольшое количество данных и увеличивается. Например изображение котика масштабируется, сдвигается, другим способом корежится — и соответственно меняется описание того, что в данном элементе датасета (размеры объекта в Kitti-файле для задач Computer Vision)

Согласен про бизнес-логику, но в этом месте статьи я изящно (смайлик) показал способ быстро захардкодить странное. А за странным бизнес иногда прибегает в пятницу вечером со словами что "все забыли, сорян, но в субботу оно должно работать, потому что Урюпинск с утра будет на федеральных каналах". Дописывать ядро бизнес-логики и выкатывать на прод в пятницу не всегда хочется, поэтому можно например вот так, по-простому. С одновременным постом в трекер задачи на техдолг.

(здесь был ответ на комментарий про бизнес-логику, который потом перенес в правильную ветку)

Я не пропагандирую какой-то конкретный шаблонизатор, но да, склоняюсь к минимизации логики внутри шаблонов (форматтеры и предикаты по спискам — ОК, выполнение произвольного кода — не ОК). Шаблонизирование через format хорошо, если в модели нет массивов и условий (то есть для ряда случаев — вполне себе метод).


Ну и скорее статья дискутирует с методом, когда подобные артефакты создаются путем конкатенации строчек внутри кода. Такой подход я встречал неоднократно (особенно почему-то любят так мучать SQL). Результат — очень мутный код.


Для сравнения — добавил в гитхабе в template_3.py класс, который формирует SQL путем конкатенации строк по той же модельке. Довольно мутная штука в плане наглядности:


class SqlAntipattern(object):
    def render(self, m):
        if m["typeList"]:
            return self.render_typelist(m)
        if m["typeCountGroupBy"]:
            return self.render_groupby(m)

        raise Exception("Unknown query type")

    def render_where(self, m):
        sql = "WHERE "

        def eqtion(w):
            return "{}={}{}{}".format(
                w["field"],
                "'" if "quot" in w else "",
                w["eq_val"],
                "'" if "quot" in w else "")

        wheres = [eqtion(w) for w in m["where"]]
        sql += ", ".join(wheres)
        return sql + " "

    def render_orderby(self, m):
        return "ORDER BY " + m["orderBy"]

    def render_typelist(self, m):
        sql = "SELECT * FROM " + m["tableName"] + " "
        if "hasWhere" in m:
            sql += self.render_where(m)

        if "orderBy" in m:
            sql += self.render_orderby(m)

        if "limit" in m:
            sql += " LIMIT " + m["limit"]

        return sql

    def render_groupby(self, m):
        sql = "SELECT " + m["groupColumn"]
        sql += ", COUNT(*) FROM " + m["tableName"] + " "
        sql += " GROUP BY " + m["groupColumn"]

        return sql

Information

Rating
Does not participate
Location
Зеленоград, Москва и Московская обл., Россия
Registered
Activity