В рамках пилотного проекта необходимо протестировать возможность ограничения доступа к данным (RLS) как для разных категорий пользователей, так и отдельных пользователей. Как я понял, данный функционал становится доступен при интеграции с AD, в блоке RBAC. В рамках пилотного проекта не предусмотрена интеграция с AD, только использование встроенных пользователей LuxmsBI. Слышал, что есть вариант реализации ограничения доступа к данным без использования AD и модуля RBAC, но настройку придётся выполнять прямыми INSERT-ами в БД mi.
Возможно ли выложить инструкцию по настройке RLS вручную, при помощи запросов в БД mi и без использования AD?
Настройка доступа пользователей к данным, которые отдает куб, может производиться insert’ами в таблицу koob.user_cube_maps, пример:
INSERT INTO koob.user_cube_maps (user_id, cube_id, filter) VALUES (0, '<ID cube>', 'field1=''value1''');
Где
user_id - id пользователя из таблицы adm.users
cube_id - id куба из таблицы koob.cubes
‘field1=“value1”’ - пример задания условия. Здесь field1 - это наименование поля в запросе, которым формируется куб, value1 - значение.
Т.е. строка из поля filter добавляется во where запроса, которым формируется куб.
Спасибо за подробный ответ.
Ещё несколько вопросов по теме:
- Вижу, что в koob.user_cube_maps есть ещё поле “lpe”. Получится ли предоставить правила заполнения этого поля? Будет здорово, если с примерами.
- Можно ли делать настройки ограничений для содержимого таблицы adm.user_groups, т.е. для групп пользователей?
- Вижу, что есть таблица koob.user_dimension_maps. Полагаю, что она может использоваться для ограничений доступа к данным измерений. Поскажите, так ли это? Если да, получится ли описать правила заполнения этой таблицы? Будет здорово, если с примерами.
В заметке https://help.luxmsbi.com/-925 увидел такую информацию:
Для того чтобы ограничить доступ пользователей к результату запроса прямо внутри него можно воспользоваться следующей конструкцией:
${access_filters()}
На данный момент это единственное упоминание такого способа ограничения доступа к данным.
Есть ли возможность предоставить более развёрнутое описание фильтра с несколькими “живыми” примерами применения?
- Поле lpe - служебное, заполняется автоматически
- Пока такой возможности нет, планируем в будущие версии добавить
- Уточним позже
Данный параметр подставляет в запрос условие из поля filter таблицы koob.user_cube_maps, которое прописано для указанного пользователя и куба.
Попытаюсь подробнее описать как работает механизм:
Предположим подготовлен куб
select field_measures, field_dimensions from table
и в таблице koob.user_cube_maps указано ограничение
в общем случае перед выполнением запрос будет обернут в еще один запрос с указанием агрегационных функций и всех фильтров
select sum(field_measures) as field_measures, field_dimensions from(
select field_measures, field_dimensions from table) t
where ${filters()} and ${access_filters()}
group by field_dimensions
где далее фильтры будут заменены и в результате мы получим следующее (если не было выбрано ни одного фильтра в управляющем дэше)
select sum(field_measures) as field_measures, field_dimensions from(
select field_measures, field_dimensions from table) t
where 1=1 and org=1111
group by field_dimensions
все это под капотом и происходит незаметно для пользователей, но иногда возникают ситуации, когда запрос куба достаточно сложный и внутренний select выполняется очень долго собирая всю информацию, а мы знаем (например), что в koob.user_cube_maps прописано условие, по которому для пользователей накладывается ограничение на доступную организацию. Что бы ускорить запрос, мы можем самостоятельно прописать фильтр внутри запроса, что ограничит вложенные запросы и увеличит скорость выполнения.
select field_measures, field_dimensions from table where ${filters()} and ${access_filters()}
что на этапе выполнения под капотом будет преобразовано в запрос
select sum(field_measures) as field_measures, field_dimensions from(
select field_measures, field_dimensions from table where 1=1 and org=1111) t
where 1=1 and org=1111
group by field_dimensions
в настройках куба должно быть указано is_template:1, в этом случае указанные фильтры внутри запроса будут учтены, а если еще указать skip_where:1, то запрос будет преобразован в
select sum(field_measures) as field_measures, field_dimensions from(
select field_measures, field_dimensions from table where 1=1 and org=1111) t
group by field_dimensions
Большое спасибо за очень подробный ответ, много интересных деталей.
Сам механизм RLS протестировал - работает как описано.
Пока тестировал, увидел, что можно использовать не только “=”, но и, например, “>” или “<”.
Подскажите, какие ещё операторы можно использовать при настройке RLS?
Также вижу, что на таблице есть ограничение UNIQUE (user_id, cube_id). которое не даст завести более одного правила на куб для пользователя. Получается, по нескольким атрибутам куб не получится ограничить, правильно?
-
Всё верно, можно использовать: “=”, “<”, “>”, “!=”, “and”, “or”, “in ”, выражения в “()”.
Стоит учитывать, что LPE не является SQL, поэтому должен записываться в нижнем регистре(lowercase). -
Правил на куб для пользователя можно использовать более 1-го.
Ограничение по нескольким dimension/атрибутов возможно с помощью операторов из пункта “1”.
Можно составлять любое количество выражений со сложной логикой.
Подскажите, получится ли предоставить пример сложного правила, провернного на реальных пример с lpe, который будет при этом сгенерирован?
Пробовал написать конфигурацию с in, and и or и каждый раз генерируется невалидный lpe и как результат - неправильно работают дэшборды.
Прикладываю рабочие варианты правил из реальных примеров:
1 :
(( upcode = '000000R063' or upcode = null) and ( loc_id = 71110 or loc_id = 6 or loc_id = 71079 or loc_id = 5 or loc_id = 71042 or loc_id = 71051 or loc_id = 71075 or loc_id = 71064 or loc_id = 71046 or loc_id = 71069 or loc_id = 71044 or loc_id = 71054))
2 :
( deps = 'ЦДИМ') or ( department_id = -2001) or ( upcode = '0000002151') or ( invzak = '0000002151')
3 :
upcode in ['0000005868', '000000R084']
Пробую следующие варианты и всё выходит не то.
Вариант 1:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'(dim1 in [5312, 5392, 5461]) and (dim2 = 2022)'
);
Сгенерированный lpe:
["expr",["and",["()",["in","dim1",["[",5312,5392,5461]]],["()",["=","dim2",2022]]]]
В where запроса:
WHERE (((in(dim1,5312 [ 5392))) AND (("dim2" = 2022)))
Результат: запросы к кубу падают.
.
.
.
Вариант 2:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'dim1 in [''5312'', ''5392'', ''5461''] and dim2 = 2022'
);
Сгенерированный lpe:
["expr",["in","dim1",["and",["[",["'","5312"],["'","5392"],["'","5461"]],["=","dim2",2022]]]]
В where запроса:
WHERE (in(dim1,('5312' [ '5392') AND ("dim2" = 2022)))
Результат: запросы к кубу падают.
.
.
.
Вариант 3:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'((dim1 = 5312 or dim1 = 5392 or dim1 = 5461) and dim2 = 2022)'
);
Сгенерированный lpe:
["expr",["()",["and",["()",["or",["=","dim1",5312],["or",["=","dim1",5392],["=","dim1",5461]]]],["=","dim2",2022]]]]
В where запроса:
WHERE (((((dim1 = 5312) OR ((dim1 = 5392) OR (dim1 = 5461)))) AND ("dim2" = 2022)))
Результат: неcмотря на то, что формально запрос выполнится, в разделе с OR присутствует некорректная группировка изначального условия скобками.
.
.
.
Вариант 4:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'dim1 in [5312, 5392, 5461]'
);
Сгенерированный lpe:
["expr",["in","dim1",["[",5312,5392,5461]]]
В where запроса:
WHERE (in(dim1,5312 [ 5392))
Результат: запросы к кубу падают.
.
.
Что необходимо сделать, чтобы указанные примеры начали генерировать корректный sql?
Попробуйте вместо in
использовать знак равно
dim1 = [5312, 5392, 5461]
Большое спасибо за подсказку!
Вариант 4:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'dim1 = [5312, 5392, 5461]'
);
Сгенерированный lpe:
["expr",["=","dim1",["[",5312,5392,5461]]]
В where запроса:
WHERE (dim1 IN (5312, 5392, 5461))
Результат: запросы строятся корректно.
.
.
.
Вариант 5:
INSERT INTO koob.user_cube_maps
(
user_id,
cube_id,
filter
)
VALUES
(
17,
'cube',
'((dim1 = 5312 and dim2 = 2022) or dim1 = 5392 and dim1 = 5461) and dim3 = ''xxx'''
);
Сгенерированный lpe:
["expr",["and",["()",["or",["()",["and",["=","dim1",5312],["=","dim2",2022]]],["and",["=","dim1",5392],["=","dim1",5461]]]],["=","dim3",["'","xxx"]]]]
В where запроса:
WHERE ((((((dim1 = 5312) AND ("dim2" = 2022))) OR ((dim1 = 5392) AND (dim1 = 5461)))) AND ("dim3" = 'xxx'))
Если немного разбить, то можно увидеть, что условие приобрело новые очертания:
WHERE
(
(
(
(
(
(dim1 = 5312) AND
("dim2" = 2022)
)
) OR
(
(dim1 = 5392) AND
(dim1 = 5461)
)
)
) AND
(
"dim3" = 'xxx'
)
)
Часть dim1 = 5392 AND dim1 = 5461 стала единой и изначальное условие получается искаженным. Еще довольно странно выглядит, что названия некоторых полей автоматически берутся в кавычки, а некоторые - нет.
Подскажите, является ли такой разбор выражений предусмотренным?