Ограничение доступа к данным

В рамках пилотного проекта необходимо протестировать возможность ограничения доступа к данным (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 запроса, которым формируется куб.

Спасибо за подробный ответ.

Ещё несколько вопросов по теме:

  1. Вижу, что в koob.user_cube_maps есть ещё поле “lpe”. Получится ли предоставить правила заполнения этого поля? Будет здорово, если с примерами.
  2. Можно ли делать настройки ограничений для содержимого таблицы adm.user_groups, т.е. для групп пользователей?
  3. Вижу, что есть таблица koob.user_dimension_maps. Полагаю, что она может использоваться для ограничений доступа к данным измерений. Поскажите, так ли это? Если да, получится ли описать правила заполнения этой таблицы? Будет здорово, если с примерами.

В заметке https://help.luxmsbi.com/-925 увидел такую информацию:

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

${access_filters()}

На данный момент это единственное упоминание такого способа ограничения доступа к данным.
Есть ли возможность предоставить более развёрнутое описание фильтра с несколькими “живыми” примерами применения?

  1. Поле lpe - служебное, заполняется автоматически
  2. Пока такой возможности нет, планируем в будущие версии добавить
  3. Уточним позже

Данный параметр подставляет в запрос условие из поля 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
1 лайк

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

Сам механизм RLS протестировал - работает как описано.

Пока тестировал, увидел, что можно использовать не только “=”, но и, например, “>” или “<”.
Подскажите, какие ещё операторы можно использовать при настройке RLS?

Также вижу, что на таблице есть ограничение UNIQUE (user_id, cube_id). которое не даст завести более одного правила на куб для пользователя. Получается, по нескольким атрибутам куб не получится ограничить, правильно?

  1. Всё верно, можно использовать: “=”, “<”, “>”, “!=”, “and”, “or”, “in ”, выражения в “()”.
    Стоит учитывать, что LPE не является SQL, поэтому должен записываться в нижнем регистре(lowercase).

  2. Правил на куб для пользователя можно использовать более 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 стала единой и изначальное условие получается искаженным. Еще довольно странно выглядит, что названия некоторых полей автоматически берутся в кавычки, а некоторые - нет.
Подскажите, является ли такой разбор выражений предусмотренным?