Реализация ограничений ACL, больше, чем разрешить / запретить - PullRequest
8 голосов
/ 26 мая 2011

Я разработал небольшую, но эффективную среду в стиле MVC для использования в приложении, и я реализую проверку ACL для каждого запроса.

Быстрые детали: PHP 5.3+; MySQL 5.1+; Пользовательские рамки, "MVC-like"

На данный момент проверка ACL проста: " deny-if-not white-list "; Каждому group может быть назначено разрешение для определенных обработчиков запросов. Например:

privilege                       permission
+----------+---------------+    +---------------+---------------+
| group_id | permission_id |    | permission_id | handler_key   |
+----------+---------------+    +---------------+---------------+
|     1    |       1       |    |       1       | lorem_ipsum   |
|     1    |       2       |    |       2       | hello_world   |
|     2    |       3       |    |       3       | foobar        |
+----------+---------------+    +---------------+---------------+

(user и group исключены для краткости, но в их моделях нет ничего необычного )

В любом случае, моя инфраструктура направляет URI к соответствующему handler_key через таблицу обработчика / пути ( для отделения архитектуры файловой системы ). Затем запрос отправляется обработчику, учитывая group_id, связанный с для этого запрос занесен в белый список handler_key.

Мне любопытно, каков наилучший подход для реализации сохранения / проверки произвольных ( определенных пользователем ) ограничений? Примерами примеров могут быть:

  • Разрешить указанной группе вызывать обработчик только по рабочим дням с 8:00 до 17:00.
  • Разрешить только указанной группе вызывать обработчик для изменения "собственных" данных; то есть: данные, созданные ассоциированным user. Эта проверка может включать в себя, возможно, проверку поля user_id, связанного с контентом, который будет изменен обработчиком, и user_id, связанного с запросом

У меня был столбец flags, однако он не рассчитан на будущее с введением дополнительных требований к функциям, группам и ограничениям. Я думал в следующем направлении, но что использовать?

permission
+---------------+----------------------------+
| permission_id | handler_key   | constraint |
+---------------+---------------+------------+
|       1       | lorem_ipsum   |     ?      |
|       2       | hello_world   |     ?      |
|       3       | foobar        |     ?      |
+---------------+---------------+------------+

Ненужные уточнения:

( Примечание: здесь был введен код, а не copypasta из проекта )

Чтобы уточнить некоторые жаргон здесь; обработчики (в частности, веб-обработчики), по сути, контроллеры для тех, кто знаком с архетипом MVC.

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

<?php
    $meta = array('subhandlers' => array());
    return function($request, $response) use($meta){
        $response['foo'] = 'bar';
    };

Мой фреймворк использует веб-обработчики и API-обработчики ; веб-обработчики подают данные в объект ответа (в основном, это набор иерархических просмотров ), который генерирует HTML. Данные получают путем вызова обработчиков API, которые просто возвращают необработанные данные (обработчики API можно рассматривать как представления модель , возвращаясь к типичному MVC)

Составные обработчики - это, по сути, уровень абстракции, так как они сами являются обработчиками, которые вызывают обработчики для агрегирования данных. Моя текущая реализация проверки ACL выполняет краткую проверку всех вложенных обработчиков (через $meta, переменную массива, объявленную в качестве заголовка метаданных для обработчика). Например:

<?php
    $meta = array('subhandlers' => array('my_subhandler'));
    return function($request, $response) use($meta){
        $someData = Caller::call('my_subhandler', array($request, $response));
        $response->bind($someData);
    };

Ответы [ 2 ]

4 голосов
/ 26 мая 2011

В видео, которое я разместил в своем комментарии, есть идеи, схожие с теми, которыми вы поделились, но без кода.

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

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

Следующим шагом является определение какой-либо системы обозначений или структуры данных, которую можно легко проанализировать и проверить, например, с учетом ограничений по времени у вас есть следующие возможности:

  • конкретные даты (2011-05-26)
  • диапазоны даты и времени (с 2011-05-26 по 2011-05-31)
  • рекурсивные даты (201x-05-26 или каждая пятница)
  • логические (и / или / xor) операторы

Если у вас есть нотация с проппером, вы можете легко проанализировать и проверить это с помощью токенизации правила и, возможно, используя что-то DatePeriod или DateInterval или даже оператор модуля как делает crontab.

Ваш второй пример:

Разрешить только данной группе вызывать обработчик для изменения «собственных» данных; то есть: данные, созданные ассоциированным пользователем.

Для меня звучит как простой ACL:

  • ресурс: конкретные данные
  • роль: конкретный пользователь

Тогда, конечно, у вас есть более сложные правила, такие как:

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

Я думаю, что такого рода правила должны быть специфичны для логики приложения, и настоящее универсальное решение будет чрезвычайно сложно реализовать, - сказал Зед Шоу в своем выступлении, предлагая полное решение, которое использует только 400 строк кода, Мне было бы очень интересно узнать, как он это сделал.

Флаги (хранящиеся в битах) являются отличным (хотя и загадочным) способом определения комбинации одного или нескольких ограничений, но, по моему опыту, лучше, если вы определите все ограничения apriori.

Поскольку вы, похоже, не знаете точно, какие ограничения вы хотите проверить, я предлагаю вам создать нотацию для нескольких типов ограничений, которые вы хотите проверить:

  • по времени
  • на основе пользователя / ресурса
  • ...

И затем реализовать методы, которые анализируют (возможно, с помощью обозначения, которое подразумевает версию, чтобы вы могли выполнить миграцию в будущем) и проверяют все ограничения.

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

2 голосов
/ 26 мая 2011

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

( Пожалуйста, критикуйте и / или высмеивайте и /или более пяти это предложение в качестве ордера )

Запрос на проверку, имеет ли пользователь разрешения, может, для этих целей, рассматриваться как просто другой запрос, поэтому требуется собственный обработчик .Например:

permission
+---------------+--------------------------------------+- - - - - -+
| permission_id | handler_key | constraint_handler_key | arguments :
+---------------+-------------+------------------------+ - - - - - +
|       1       | lorem_ipsum | user_check_owner       |           :
|       2       | hello_world | user_check_owner       |           :
|       3       | foobar      | time_check             |           :
+---------------+-------------+------------------------+ - - - - - +

С добавлением столбца NULL -able constraint_handler_key можно программно создавать новые ограничения и делегировать их административно.

Когда запрос запускается,Framework собирает цепочку обработчиков и сравнивает ее с белым списком, как это уже делается.Если существует constraint_handler_key (, возможно, с аргументами, как предлагает приведенная выше таблица ), он выполняет поиск в handlerTable, связанном с этим типом запроса:

// web handlers handlerTable example
return array(
    'lorem_ipsum' => PATH_WEB_HANDLERS . 'path/to/lorem_ipsum.handler.php',
);

// acl handlers handlerTable, follows same format
return array(
    'time_check' => PATH_ACL_HANDLERS . 'time/check.handler.php',
);

( Обработчики API также идентичны )

Ожидается, что обработчик ACL будет возвращать только логические значения, продолжая или завершая последовательность проверки прав доступа и, следовательно, весь запрос.

// time_check acl handler, allow if current time between 9am - 5pm
return function($request){
    $dayBegin = time() - (time() % 86400);
    return (time() > ($dayBegin + 32400) && ($dayBegin + 61200) > time());
};

Случаи пропуска constraint_handler_key s рассматриваются как базовые проверки в белом списке; allow-if / deny-if-not .

Итак, каталог моего приложения начнет выглядеть так:

:
+- application/
|   +- config/
|   +- views/
|   +- handlers/
|       +- acl/
|       +- api/
|       +- web/
:
...