Microsegment.ru
  • Главная страница
  • О проекте
  • Портфолио
  • Блог
Системы

Анализ правил доступа в Tessa

Анализ правил доступа в Tessa
Системы

Согласно общей концепции анализа модели предоставления прав в информационной системе квадрига «роль — условия — разрешения — объект» в Tessa является квантом модели предоставления прав, и правило доступа должно быть логичным кластером подобных квантовых объектов в общей модели предоставления прав в системе. Далее предпринята попытка анализа подобных кластеров-правил доступа.

Выгрузка данных из БД Tessa¶

Далее представлен код MS SQL, предназначенный для выгрузки данных из базы данных (далее БД) Tessa, которые требуются для кластерного анализа модели предоставления прав в Tessa. Однако, в целях обеспечения безопасности эксплуатационных данных для разработки кластерного анализа предлагается использовать тестовые данные, сгенерированные с помощью генератора датафреймов, разработанного в Microsegment.ru.

-- Все правила доступа с русским переводом параметров
SELECT  kp.ID AS [ID правила доступа],
        kp.Caption AS [Название правила доступа],
        CASE WHEN kp.IsDisabled ='1' THEN 'True' ELSE 'False' END AS [Правило отключено],
        CASE WHEN kp.IsRequired ='1' THEN 'True' ELSE 'False' END AS [Всегда проверять правило],
        CASE WHEN kp.IsExtended ='1' THEN 'True'ELSE 'False' END AS [РПД],
        CASE WHEN kp.Conditions LIKE '%ConditionTypeID%' THEN 'True' ELSE 'False' END AS [Типы условий],
        -- Разрешения из правил доступа
        CASE WHEN kp.CanCreateCard ='1' THEN 'True' ELSE 'False' END AS [Создание карточки],
        CASE WHEN kp.CanReadCard ='1' THEN 'True' ELSE 'False' END AS [Чтение карточки],
        CASE WHEN kp.CanEditCard ='1' THEN 'True' ELSE 'False' END AS [Редактирование карточки],
        CASE WHEN kp.CanEditFiles ='1' THEN 'True' ELSE 'False' END AS [Редактирование файлов],
        CASE WHEN kp.CanAddFiles ='1' THEN 'True' ELSE 'False' END AS [Добавление файлов],
        CASE WHEN kp.CanEditRoute ='1' THEN 'True' ELSE 'False' END AS [Редактирование маршрута],
        CASE WHEN kp.CanDeleteCard ='1' THEN 'True' ELSE 'False' END AS [Удаление карточки],
        CASE WHEN kp.CanStartProcess ='1' THEN 'True' ELSE 'False' END AS [Инициация типового процесса отправки задач],
        CASE WHEN kp.CanEditNumber ='1' THEN 'True' ELSE 'False' END AS [Ручное редактирование номера],
        CASE WHEN kp.CanCreateResolutions ='1' THEN 'True' ELSE 'False' END AS [Создание резолюций],
        CASE WHEN kp.CanDeleteFiles ='1' THEN 'True' ELSE 'False' END AS [Удаление всех файлов],
        CASE WHEN kp.CanEditOwnFiles ='1' THEN 'True' ELSE 'False' END AS [Редактирование собственных файлов].
        CASE WHEN kp.CanDeleteownFiles ='1' THEN 'True'ELSE 'False' END AS [Удаление собственных файлов],
        CASE WHEN kp.CansignFiles ='1' THEN 'True' ELSE 'False' END AS [Подписание файлов],
        CASE WHEN kp.CanAddTopics ='1' THEN 'True'ELSE 'False'END AS [Создание обсуждений].
        CASE WHEN kp.CanSuperModeratorMode ='1' THEN 'True'ELSE 'False' END AS [Права супермодератора],
        CASE WHEN kp.CanSubscribeForNotifications = '1' THEN 'True' ELSE 'False' END AS [Подписка на уведомления],
        CASE WHEN kp.CanCreateTemplateAndCopy ='1' THEN 'True' ELSE 'False' END AS [Создание шаблона и копирование],
        CASE WHEN kp.CanSkipStages ='1' THEN 'True' ELSE 'False' END AS [Пропуск этапов],
        CASE WHEN kp.CanFullRecalcRoute ='1' THEN 'True' ELSE 'False' END AS [Полный пересчет маршрута].
        CASE WHEN kp.CanEditMyMessages ='1' THEN 'True' ELSE 'False' END AS [Редактирование своих сообщений],
        CASE WHEN kp.CanEditAllMessages ='1' THEN 'True' ELSE 'False' END AS [Редактирование всех сообщений],
        CASE WHEN kp.CanReadAllTopics ='1' THEN 'True' ELSE 'False' END AS [Чтение обсуждений],
        CASE WHEN kp.CanReadAndSendMessageInAllTopics ='1' THEN 'True' ELSE 'False' END AS [Чтение и отправка сообщений]
FROM KrPermissions (NOLOCK) kp;

-- Обогащение правил доступа дополнительными данными о ролях
SELECT DISTINCT
    -- Правила доступа
    kpr.ID AS [ID правила доступа],
    -- Роли
    kpr.RoleID AS [ID роли],
    kpr.RoleName AS [Название роли]
FROM krPermissionRoles (NOLOCK) kpr;

-- Обогащение правил доступа дополнительными данными о типах документов
SELECT DISTINCT
    -- Правила доступа
    kpt.ID AS [ID правила доступа],
    -- Тип карточки
    kpt.TypeCaption AS [ID ЛФО типа карточки]
    dbo.Localize(kpt.TypeCaption, 25) AS [Тип карточки]
FROM KrPermissionTypes (NOLOCK) kpt;

-- Обогащение правил доступа дополнительными данными о состояниях документов
SELECT DISTINCT
    -- Правила доступа
    kpt.ID AS [ID правила доступа],
    -- Состояние карточки
    kps.StateName AS [ID ЛФО состояния карточки]
    dbo.Localize(kps.StateName, 25) AS [Состояние карточки]
FROM KrPermissionStates (NOLOCK) kps

-- Расширенные правила доступа (РПД)
SELECT
DISTINCT
    -- Правила доступа
    kp.ID AS [ID правила доступа],
    -- Параметры РПД
    kpecr.SectionName AS [РПД. Секция карточки].
    kpecrf.FieldName AS [РПД. Поле карточки],
    kpecr.AccessSettingName AS [РПД. Разрешение],
    dbo.Localize(kpecr.AccesssettingName, 25) AS [РПД. Разрешение (рус)]
FROM KrPermissions AS kp
LEFT JOIN KrPermissionExtendedcardRules (NOLOCK) kpecr ON kpecr.ID = kp. ID
LEFT JOIN KrPermissionExtendedcardRulefields (NOLOCK) kpecrf ON kpecrf. ID = kp.ID;

-- Вхождение PersonalRoles в любые Roles, кроме ContextRoles
SELECT  pr.ID AS [ID пользователя],
        pr.Name AS [Имя пользователя],
        pr.Position AS [Должность пользователя], 
        pr.AccessLevelID AS [Уровень доступа пользователя], 
        pr.LoginTypeID AS [Тип учетной записи пользователя], 
        pr.Login AS [Логин пользователя],
        CASE WHEN pr.Blocked ='1' THEN 'True' END AS [Блокировка учетной записи пользователя], 
        r.ID AS [ID роли], 
        r.Name AS [Название роли], 
        r.TypeID AS [Тип роли]
FROM Roles (NOLOCK)r
LEFT JOIN RoleUsers (NOLOCK) ru ON ru.ID = r.ID
LEFT JOIN PersonalRoles (NOLOCK) pr ON pr.ID - ru.UserID
WHERE (ru. IsDeputy = O OR ru.IsDeputy IS NULL)
ORDER BY pr.Name, r.Name;

-- ContextRoles
SELECT cr.ID AS [ID роли],
        cr.SqlText AS [Код SQL]
FROM ContextRoles (NOLOCK) cr;
-- Для выявления вхождения идентификаторов ролей в коды контекстных ролей
-- (очень долгая операция, лучше реализовать локально на Python)
--LEFT JOIN Roles (NOLOCK) r ON cr.SqlText LIKE '%'+CONVERT(VARCHAR(50), .ID)+'%'

Загрузка библиотек¶

In [8]:
import pandas as pd
import numpy as np

Загрузка данных¶

In [10]:
# Данные из таблицы KrPermissions, предварительно выгруженные из БД Tessa
KrPermissions = pd.read_csv('files/KrPermissions.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(KrPermissions.info())
KrPermissions.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 187 entries, 0 to 186
Data columns (total 30 columns):
 #   Column                                      Non-Null Count  Dtype 
---  ------                                      --------------  ----- 
 0   ID правила доступа                          187 non-null    object
 1   Название правила доступа                    187 non-null    object
 2   Правило отключено                           187 non-null    bool  
 3   Всегда проверять правило                    187 non-null    bool  
 4   РПД                                         187 non-null    bool  
 5   Типы условий                                187 non-null    bool  
 6   Создание карточки                           187 non-null    bool  
 7   Чтение карточки                             187 non-null    bool  
 8   Редактирование карточки                     187 non-null    bool  
 9   Удаление карточки                           187 non-null    bool  
 10  Добавление файлов                           187 non-null    bool  
 11  Редактирование собственных файлов           187 non-null    bool  
 12  Редактирование файлов                       187 non-null    bool  
 13  Удаление собственных файлов                 187 non-null    bool  
 14  Удаление всех файлов                        187 non-null    bool  
 15  Инициация типового процесса отправки задач  187 non-null    bool  
 16  Редактирование маршрута                     187 non-null    bool  
 17  Пропуск этапов                              187 non-null    bool  
 18  Полный пересчет маршрута                    187 non-null    bool  
 19  Ручное редактирование номера                187 non-null    bool  
 20  Создание резолюций                          187 non-null    bool  
 21  Подписание файлов                           187 non-null    bool  
 22  Создание обсуждений                         187 non-null    bool  
 23  Права супермодератора                       187 non-null    bool  
 24  Подписка на уведомления                     187 non-null    bool  
 25  Создание шаблона и копирование              187 non-null    bool  
 26  Редактирование своих сообщений              187 non-null    bool  
 27  Редактирование всех сообщений               187 non-null    bool  
 28  Чтение обсуждений                           187 non-null    bool  
 29  Чтение и отправка сообщений                 187 non-null    bool  
dtypes: bool(28), object(2)
memory usage: 8.2+ KB
None
Out[10]:
ID правила доступа Название правила доступа Правило отключено Всегда проверять правило РПД Типы условий Создание карточки Чтение карточки Редактирование карточки Удаление карточки … Создание резолюций Подписание файлов Создание обсуждений Права супермодератора Подписка на уведомления Создание шаблона и копирование Редактирование своих сообщений Редактирование всех сообщений Чтение обсуждений Чтение и отправка сообщений
0 5b5a54df-f4c3-429b-9b90-afcbfc94d904 Правило 0 False True False False True True False False … True False False False False False False False False False
1 18841597-7fd1-4dd9-a48e-ed7287cb7ca9 Правило 1 False False False False True True False False … False False False False False False False False False False
2 49097422-ab5d-43db-8d58-1c2fd2e7b951 Правило 2 False False False False True False True False … False False False False False False False False False False
3 f3c8942f-da63-456d-8d4f-c9edd97d9568 Правило 3 False True False False True True True False … False False False False False False False False False False
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 Правило 4 False False False False False False True True … True False False False False False False False False False

5 rows × 30 columns

In [11]:
# Данные из таблицы KrPermissionRoles, предварительно выгруженные из БД Tessa
KrPermissionRoles = pd.read_csv('files/KrPermissionRoles.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(KrPermissionRoles.info())
KrPermissionRoles.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 403 entries, 0 to 402
Data columns (total 3 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  403 non-null    object
 1   ID роли             403 non-null    object
 2   Название роли       403 non-null    object
dtypes: object(3)
memory usage: 9.6+ KB
None
Out[11]:
ID правила доступа ID роли Название роли
0 20336af0-1547-4441-b701-abb37eb7e80a 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 Беляева В.Д.
1 17c8a168-87ff-42ab-a499-a8af288649cf 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 Григорьев Б.Д.
2 ed9ab1be-8faa-4f18-8fc8-1efc5402342b e96d002f-ee0f-461a-b831-561ff8b457e3 Юридический отдел
3 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b Согласующий финансовых документов
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b Согласующий финансовых документов
In [12]:
# Данные из таблицы KrPermissionTypes, предварительно выгруженные из БД Tessa
KrPermissionTypes = pd.read_csv('files/KrPermissionTypes.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(KrPermissionTypes.info())
KrPermissionTypes.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 174 entries, 0 to 173
Data columns (total 3 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  174 non-null    object
 1   ID типа карточки    135 non-null    object
 2   Тип карточки        135 non-null    object
dtypes: object(3)
memory usage: 4.2+ KB
None
Out[12]:
ID правила доступа ID типа карточки Тип карточки
0 de03f571-e211-432c-9c8a-e863d673ebf6 c86fb70e-7352-480f-a710-e6b75e5cbac2 Дополнительное соглашение
1 d94cda5c-6434-4215-8245-a3ed951d652a 1293034c-e069-482c-a710-8738f6145b72 Входящий
2 bf756289-8092-477b-a03c-afb2c49fa6ae 97ed6f19-5201-441b-acee-8474be8a44db МЧД
3 9fdefb43-5469-4322-8a3d-c9229d89cb72 c86fb70e-7352-480f-a710-e6b75e5cbac2 Дополнительное соглашение
4 efe9a617-b5cc-432f-be74-620c4f57de40 NaN NaN
In [13]:
# Данные из таблицы KrPermissionStates, предварительно выгруженные из БД Tessa
KrPermissionStates = pd.read_csv('files/KrPermissionStates.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(KrPermissionStates.info())
KrPermissionStates.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 3 columns):
 #   Column                 Non-Null Count  Dtype 
---  ------                 --------------  ----- 
 0   ID правила доступа     178 non-null    object
 1   ID состояния карточки  134 non-null    object
 2   Состояние карточки     134 non-null    object
dtypes: object(3)
memory usage: 4.3+ KB
None
Out[13]:
ID правила доступа ID состояния карточки Состояние карточки
0 5549c392-541d-4667-ac61-91596128d1a6 17215e76-92fa-4586-934e-92bc85e7f91b Проект
1 36a36459-e020-4900-80a5-468ebcaf3ca6 cbae96bd-0d35-4a38-aa01-b6fd2b4b208d Зарегистрирован
2 3d74a414-af74-4d28-a331-2d8ee29312e5 d3f85efe-2808-416f-93c0-f1589f150e47 На согласовании
3 9ed92537-fb02-4cd5-bf60-bb5ec8b690ce fdffb12d-be8d-49e2-999e-b5a661dfb955 На обработке
4 14104765-d331-467f-a9ea-639e0f7d49d2 cbae96bd-0d35-4a38-aa01-b6fd2b4b208d Зарегистрирован
In [14]:
# Данные из таблицы KrPermissionExtendedcard, предварительно выгруженные из БД Tessa
KrPermissionCardRules = pd.read_csv('files/KrPermissionExtendedcard.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(KrPermissionCardRules.info())
KrPermissionCardRules.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 5 columns):
 #   Column                 Non-Null Count  Dtype 
---  ------                 --------------  ----- 
 0   ID правила доступа     5 non-null      object
 1   РПД. Секция карточки   5 non-null      object
 2   РПД. Поле карточки     5 non-null      object
 3   РПД. Разрешение        5 non-null      object
 4   РПД. Разрешение (рус)  5 non-null      object
dtypes: object(5)
memory usage: 332.0+ bytes
None
Out[14]:
ID правила доступа РПД. Секция карточки РПД. Поле карточки РПД. Разрешение РПД. Разрешение (рус)
0 5b5a54df-f4c3-429b-9b90-afcbfc94d904 Document DocumentText Write Редактирование
1 18841597-7fd1-4dd9-a48e-ed7287cb7ca9 GeneralInformation CreationDate DenyWrite Запрещено редактировать
2 49097422-ab5d-43db-8d58-1c2fd2e7b951 EmployeeCard Salary Read Чтение
3 f3c8942f-da63-456d-8d4f-c9edd97d9568 ApprovalStage Comments Append Добавление комментариев
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 BasicData Subject DenyDelete Запрещено удалять
In [15]:
# Данные из таблицы RoleUsers, предварительно выгруженные из БД Tessa
RoleUsers = pd.read_csv('files/RoleUsers.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(RoleUsers.info())
RoleUsers.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 483 entries, 0 to 482
Data columns (total 10 columns):
 #   Column                                  Non-Null Count  Dtype  
---  ------                                  --------------  -----  
 0   ID пользователя                         483 non-null    object 
 1   Имя пользователя                        483 non-null    object 
 2   Должность пользователя                  483 non-null    object 
 3   Уровень доступа пользователя            472 non-null    float64
 4   Тип учетной записи пользователя         461 non-null    float64
 5   Логин пользователя                      483 non-null    object 
 6   Блокировка учетной записи пользователя  353 non-null    object 
 7   ID роли                                 483 non-null    object 
 8   Название роли                           483 non-null    object 
 9   Тип роли                                483 non-null    int64  
dtypes: float64(2), int64(1), object(7)
memory usage: 37.9+ KB
None
Out[15]:
ID пользователя Имя пользователя Должность пользователя Уровень доступа пользователя Тип учетной записи пользователя Логин пользователя Блокировка учетной записи пользователя ID роли Название роли Тип роли
0 b554a73d-e711-404c-a92f-6b532d590f73 Комаров Р.Т. Начальник отдела 1.0 0.0 komarovrt False 0ebe84b4-137e-4020-b29e-3749d2a6310b IT-отдел 2
1 8da6a188-ec22-4d89-832a-ebbfaba2eebf Ильин О.К. Начальник отдела 0.0 0.0 ilinok NaN 3a7ba0fd-8929-438a-9b24-26a7bd547ec2 Отдел продаж 2
2 628d7ee9-3f74-4d66-bfc6-5ab086c5c903 Соколов Р.Е. Начальник отдела 1.0 1.0 sokolovre False daf6589d-885b-49ed-a347-2ea54076ea56 Отдел кадров 2
3 d12eb580-8dac-4371-bb7d-66261719caef Комаров И.А. Старший специалист 1.0 1.0 komarovia False 66d273c8-d957-4bb3-9623-3e790daa54d9 Отдел продаж 2
4 b42fa3ea-2482-460f-abd2-4a0e3531738c Смирнова О.Б. Менеджер проекта 0.0 0.0 smirnovaob True 581bcaa7-d3fe-4483-8cc2-6446e1ea33b4 Отдел продаж 2
In [16]:
# Данные из таблицы ContextRoles, предварительно выгруженные из БД Tessa
ContextRoles = pd.read_csv('files/ContextRoles.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(ContextRoles.info())
ContextRoles.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   ID роли  5 non-null      object
 1   Код SQL  5 non-null      object
dtypes: object(2)
memory usage: 212.0+ bytes
None
Out[16]:
ID роли Код SQL
0 3a39dcf7-49d7-4a5c-a765-4aa3c16a081c \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
1 48307771-7cf8-43a1-ae95-92fbf4e0d263 \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
2 899889c8-9be5-49fc-bde1-9cdf1a65e8eb \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
3 cc4461f1-02ed-465e-a4c0-ef6b13845bd4 \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
4 4a39f1d5-a3ab-4aa4-b748-1fd725321b6d \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …

Предобработка данных¶

Перемещение дополнительной информации из датафреймов с правилами в отдельные датафреймы¶

In [19]:
# Перемещение данных о правилах доступа в отдельный датафрейм 
rules_data = KrPermissions[['ID правила доступа', 'Название правила доступа', 
                            'Правило отключено', 'Всегда проверять правило', 
                            'РПД', 'Типы условий']]\
.groupby(['ID правила доступа', 'Название правила доступа', 
          'Правило отключено', 'Всегда проверять правило', 
          'РПД', 'Типы условий']).count().reset_index()
KrPermissions = KrPermissions.drop(['Название правила доступа', 
                                    'Правило отключено', 'Всегда проверять правило', 
                                    'РПД', 'Типы условий'], axis=1)

print(rules_data.info())
rules_data.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 187 entries, 0 to 186
Data columns (total 6 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        187 non-null    object
 1   Название правила доступа  187 non-null    object
 2   Правило отключено         187 non-null    bool  
 3   Всегда проверять правило  187 non-null    bool  
 4   РПД                       187 non-null    bool  
 5   Типы условий              187 non-null    bool  
dtypes: bool(4), object(2)
memory usage: 3.8+ KB
None
Out[19]:
ID правила доступа Название правила доступа Правило отключено Всегда проверять правило РПД Типы условий
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False True True False
1 0359fea5-f9d6-4911-acbe-70f82c858418 Правило 143 True False False False
2 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False False False False
3 05bd596d-c6ad-474b-80db-fdbecab66f21 Правило 124 True False False False
4 07cc452b-48c4-4176-b13d-ab576ae7afdc Правило 67 False False False False
In [20]:
# Перемещение названий ролей из правил доступа в отдельный датафрейм 
roles_name = KrPermissionRoles[['ID роли', 'Название роли']]\
.groupby(['ID роли', 'Название роли']).count().reset_index()
KrPermissionRoles = KrPermissionRoles.drop(['Название роли'], axis=1)

print(rules_data.info())
rules_data.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 187 entries, 0 to 186
Data columns (total 6 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        187 non-null    object
 1   Название правила доступа  187 non-null    object
 2   Правило отключено         187 non-null    bool  
 3   Всегда проверять правило  187 non-null    bool  
 4   РПД                       187 non-null    bool  
 5   Типы условий              187 non-null    bool  
dtypes: bool(4), object(2)
memory usage: 3.8+ KB
None
Out[20]:
ID правила доступа Название правила доступа Правило отключено Всегда проверять правило РПД Типы условий
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False True True False
1 0359fea5-f9d6-4911-acbe-70f82c858418 Правило 143 True False False False
2 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False False False False
3 05bd596d-c6ad-474b-80db-fdbecab66f21 Правило 124 True False False False
4 07cc452b-48c4-4176-b13d-ab576ae7afdc Правило 67 False False False False

Перемещение дополнительной информации из датафреймов с ролями в отдельные датафреймы¶

In [22]:
# Перемещение данных о правилах доступа в отдельный датафрейм 
user_data = RoleUsers[['ID пользователя', 
                       'Имя пользователя', 
                       'Логин пользователя', 
                       'Должность пользователя', 
                       'Уровень доступа пользователя', 
                       'Тип учетной записи пользователя', 
                       'Блокировка учетной записи пользователя']]\
.groupby(['ID пользователя', 
          'Имя пользователя', 
          'Логин пользователя', 
          'Должность пользователя', 
          'Уровень доступа пользователя', 
          'Тип учетной записи пользователя', 
          'Блокировка учетной записи пользователя'], 
         # Не удалять строки с пропусками
         dropna=False)\
.count().reset_index()
user_data = user_data[~user_data['ID пользователя'].isnull()]
RoleUsers = RoleUsers.drop(['Имя пользователя', 
                            'Логин пользователя', 
                            'Должность пользователя', 
                            'Уровень доступа пользователя', 
                            'Тип учетной записи пользователя', 
                            'Блокировка учетной записи пользователя'], axis=1)

print(user_data.info())
user_data.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 216 entries, 0 to 215
Data columns (total 7 columns):
 #   Column                                  Non-Null Count  Dtype  
---  ------                                  --------------  -----  
 0   ID пользователя                         216 non-null    object 
 1   Имя пользователя                        216 non-null    object 
 2   Логин пользователя                      216 non-null    object 
 3   Должность пользователя                  216 non-null    object 
 4   Уровень доступа пользователя            211 non-null    float64
 5   Тип учетной записи пользователя         206 non-null    float64
 6   Блокировка учетной записи пользователя  159 non-null    object 
dtypes: float64(2), object(5)
memory usage: 11.9+ KB
None
Out[22]:
ID пользователя Имя пользователя Логин пользователя Должность пользователя Уровень доступа пользователя Тип учетной записи пользователя Блокировка учетной записи пользователя
0 00000000-0000-0000-0000-000000000002 Бухгалтерские сервисы accounting_services Сервис 0.0 2.0 False
1 00000000-0000-0000-0000-000000000003 ИТ-сервисы it_services Сервис 0.0 2.0 False
2 00000000-0000-0000-0000-000000000004 Сайт компании company_website Сервис 0.0 2.0 False
3 00000000-0000-0000-0000-000000000005 Робот службы безопасности security_service_robot Робот 1.0 2.0 False
4 00000000-0000-0000-0000-000000000006 Робот финансовой службы financial_service_robot Робот 0.0 2.0 False
In [23]:
# Перемещение данных о правилах доступа в отдельный датафрейм 
role_name = RoleUsers[['ID роли', 'Название роли']]\
.groupby(['ID роли', 'Название роли']).count().reset_index()
RoleUsers = RoleUsers.drop(['Название роли'], axis=1)

print(role_name.info())
role_name.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 429 entries, 0 to 428
Data columns (total 2 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        429 non-null    object
 1   Название роли  429 non-null    object
dtypes: object(2)
memory usage: 6.8+ KB
None
Out[23]:
ID роли Название роли
0 00000000-0000-0000-0000-000000000002 Бухгалтерские сервисы
1 00000000-0000-0000-0000-000000000003 ИТ-сервисы
2 00000000-0000-0000-0000-000000000004 Сайт компании
3 00000000-0000-0000-0000-000000000005 Робот службы безопасности
4 00000000-0000-0000-0000-000000000006 Робот финансовой службы
In [24]:
# Перемещение данных од известных ролях в отдельный датафрейм
roles = RoleUsers[RoleUsers['ID роли'] != 'Unknown'].drop_duplicates()

print(roles.info())
roles.head(5)
<class 'pandas.core.frame.DataFrame'>
Index: 476 entries, 0 to 482
Data columns (total 3 columns):
 #   Column           Non-Null Count  Dtype 
---  ------           --------------  ----- 
 0   ID пользователя  476 non-null    object
 1   ID роли          476 non-null    object
 2   Тип роли         476 non-null    int64 
dtypes: int64(1), object(2)
memory usage: 14.9+ KB
None
Out[24]:
ID пользователя ID роли Тип роли
0 b554a73d-e711-404c-a92f-6b532d590f73 0ebe84b4-137e-4020-b29e-3749d2a6310b 2
1 8da6a188-ec22-4d89-832a-ebbfaba2eebf 3a7ba0fd-8929-438a-9b24-26a7bd547ec2 2
2 628d7ee9-3f74-4d66-bfc6-5ab086c5c903 daf6589d-885b-49ed-a347-2ea54076ea56 2
3 d12eb580-8dac-4371-bb7d-66261719caef 66d273c8-d957-4bb3-9623-3e790daa54d9 2
4 b42fa3ea-2482-460f-abd2-4a0e3531738c 581bcaa7-d3fe-4483-8cc2-6446e1ea33b4 2

Кластеризация правил и ролей¶

Правила и роли не дающие прав пользователям¶

In [27]:
# Связка полной информации о ролях с идентификаторами правил,
# в которых роли используются
rules_roles = pd.merge(KrPermissionRoles, 
                       roles, 
                       on='ID роли', how='left')

rules_roles = pd.merge(rules_roles, 
                       rules_data[['ID правила доступа', 'Правило отключено']], 
                       on='ID правила доступа', how='left')

print(rules_roles.info())
rules_roles.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3655 entries, 0 to 3654
Data columns (total 5 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  3655 non-null   object
 1   ID роли             3655 non-null   object
 2   ID пользователя     3655 non-null   object
 3   Тип роли            3655 non-null   int64 
 4   Правило отключено   3655 non-null   bool  
dtypes: bool(1), int64(1), object(3)
memory usage: 117.9+ KB
None
Out[27]:
ID правила доступа ID роли ID пользователя Тип роли Правило отключено
0 20336af0-1547-4441-b701-abb37eb7e80a 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 1 False
1 17c8a168-87ff-42ab-a499-a8af288649cf 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 1 False
2 ed9ab1be-8faa-4f18-8fc8-1efc5402342b e96d002f-ee0f-461a-b831-561ff8b457e3 8d0dc4c3-be5b-4294-82cf-9422c7c00eae 2 True
3 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b 776d348c-5e78-45f6-b87d-6f1fbe205bbe 0 False
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b e932ad1c-5331-4dfd-82b0-b5f45ca45c21 0 False
In [28]:
# Правила с групповыми ролями, но не контекстными, по которым практически
# не возможно отследить, кому они предоставляют права
rules_not_contextual_roles = rules_roles[rules_roles['Тип роли'] != 4]

print('-'*5, 'Правила без контекстных ролей', '-'*5)
print(rules_roles.info())
rules_roles.head(5)
----- Правила без контекстных ролей -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3655 entries, 0 to 3654
Data columns (total 5 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  3655 non-null   object
 1   ID роли             3655 non-null   object
 2   ID пользователя     3655 non-null   object
 3   Тип роли            3655 non-null   int64 
 4   Правило отключено   3655 non-null   bool  
dtypes: bool(1), int64(1), object(3)
memory usage: 117.9+ KB
None
Out[28]:
ID правила доступа ID роли ID пользователя Тип роли Правило отключено
0 20336af0-1547-4441-b701-abb37eb7e80a 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 1 False
1 17c8a168-87ff-42ab-a499-a8af288649cf 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 1 False
2 ed9ab1be-8faa-4f18-8fc8-1efc5402342b e96d002f-ee0f-461a-b831-561ff8b457e3 8d0dc4c3-be5b-4294-82cf-9422c7c00eae 2 True
3 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b 776d348c-5e78-45f6-b87d-6f1fbe205bbe 0 False
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b e932ad1c-5331-4dfd-82b0-b5f45ca45c21 0 False
In [29]:
# Предварительный список правил с ролями без пользователей
'''
_rules_without_users = rules_not_contextual_roles[rules_not_contextual_roles['ID пользователя'].isnull()]\
.sort_values(['ID правила доступа', 'ID роли'])\
.drop(['ID пользователя', 'Должность пользователя', 
       'Уровень доступа пользователя', 'Тип учетной записи пользователя', 
       'Блокировка учетной записи пользователя'], axis=1).drop_duplicates()
'''
_rules_without_users = rules_not_contextual_roles[rules_not_contextual_roles['ID пользователя'].isnull()]\
.sort_values(['ID правила доступа', 'ID роли'])\
.drop(['ID пользователя'], axis=1).drop_duplicates()

# Правила с ролями без пользователей
rules_without_users = pd.merge(_rules_without_users['ID правила доступа'].drop_duplicates(), 
                               rules_data[['ID правила доступа', 'Название правила доступа', 'Правило отключено']], 
                               on='ID правила доступа', how='inner')
rules_without_users.to_csv('clusters/rules_without_users.csv')

print('-'*5, 'Правила с ролями без пользователей', '-'*5)
print(rules_without_users.info())
rules_without_users.head(5)
----- Правила с ролями без пользователей -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 0 entries
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        0 non-null      object
 1   Название правила доступа  0 non-null      object
 2   Правило отключено         0 non-null      bool  
dtypes: bool(1), object(2)
memory usage: 132.0+ bytes
None
Out[29]:
ID правила доступа Название правила доступа Правило отключено
In [30]:
# Роли без пользователей в правилах
'''
roles_without_users = pd.merge(_rules_without_users[['ID роли', 'Тип роли']].drop_duplicates(), 
    rules_data[['ID роли', 'Название роли']], 
    on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]
roles_without_users.to_csv('clusters/rules_without_users.csv')
'''
roles_without_users = pd.merge(_rules_without_users[['ID роли', 'Тип роли']].drop_duplicates(), 
    role_name[['ID роли', 'Название роли']], 
    on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]
roles_without_users.to_csv('clusters/rules_without_users.csv')

print('-'*5, 'Роли без пользователей (в правилах)', '-'*5)
print(roles_without_users.info())
roles_without_users.head(5)
----- Роли без пользователей (в правилах) -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 0 entries
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        0 non-null      object
 1   Название роли  0 non-null      object
 2   Тип роли       0 non-null      int64 
dtypes: int64(1), object(2)
memory usage: 132.0+ bytes
None
Out[30]:
ID роли Название роли Тип роли
In [31]:
# Предварительный список правил с ролями с пользователями
_rules_with_users = rules_not_contextual_roles[~rules_not_contextual_roles['ID пользователя'].isnull()]\
.sort_values(['ID правила доступа', 'ID роли'])\
.drop(['ID пользователя'], axis=1).drop_duplicates()

# Правила с ролями с пользователями
rules_with_users = pd.merge(_rules_with_users['ID правила доступа'].drop_duplicates(), 
                               rules_data[['ID правила доступа', 'Название правила доступа', 'Правило отключено']], 
                               on='ID правила доступа', how='inner')
rules_with_users.to_csv('clusters/rules_with_users.csv')

print('-'*5, 'Правила с ролями с пользователями', '-'*5)
print(rules_with_users.info())
rules_with_users.head(5)
----- Правила с ролями с пользователями -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 102 entries, 0 to 101
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        102 non-null    object
 1   Название правила доступа  102 non-null    object
 2   Правило отключено         102 non-null    bool  
dtypes: bool(1), object(2)
memory usage: 1.8+ KB
None
Out[31]:
ID правила доступа Название правила доступа Правило отключено
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False
1 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False
2 09c45d7d-ee39-4e35-b47b-5b40edfa20bf Правило 184 False
3 131ea06e-e001-4cec-a0f8-b31d29bd57d6 Правило 20 False
4 13d02e38-aa00-4782-9770-bca53a6838b2 Правило 22 False
In [32]:
# Роли с пользователями в правилах
'''
roles_with_users = pd.merge(_rules_with_users[['ID роли', 'Тип роли']].drop_duplicates(), 
rules_data[['ID роли', 'Название роли']], 
on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]
'''
roles_with_users = pd.merge(_rules_with_users[['ID роли', 'Тип роли']].drop_duplicates(), 
role_name[['ID роли', 'Название роли']], 
on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]

roles_with_users.to_csv('clusters/roles_with_users.csv')

print('-'*5, 'Роли с пользователями (в правилах)', '-'*5)
print(roles_with_users.info())
roles_with_users.head(5)
----- Роли с пользователями (в правилах) -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 125 entries, 0 to 124
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        125 non-null    object
 1   Название роли  125 non-null    object
 2   Тип роли       125 non-null    int64 
dtypes: int64(1), object(2)
memory usage: 3.1+ KB
None
Out[32]:
ID роли Название роли Тип роли
0 49d7a40b-b8a2-4e51-ab99-febf59a885b6 Юридический отдел 2
1 27a6ba8d-4cc5-464e-a1d9-d30daf643391 Отдел продаж 2
2 71a48819-fca5-4d4d-a9b9-0ca13e41b63f Михайлов Д.Г. 1
3 8d0dc4c3-be5b-4294-82cf-9422c7c00eae Титов Д.Д. 1
4 d1c293a6-21aa-4c45-8e77-ceb8f6fc726a Руководство 2

Правила с заблокированными пользователями¶

In [34]:
# Карточки заблокирванных пользователей
blocked_users = user_data[
    (user_data['Логин пользователя'].isna()) 
    | (user_data['Блокировка учетной записи пользователя'] == 1)
    & ~(user_data['ID пользователя'] == '11111111-1111-1111-1111-111111111111')
][['ID пользователя', 'Имя пользователя']]

# Карточки не заблокированных пользователей
non_blocked_users = user_data[
    ~(user_data['Логин пользователя'].isna()) 
    | ~(user_data['Блокировка учетной записи пользователя'] == 1)
][['ID пользователя', 'Имя пользователя']]

print('-'*5, 'Заблокированные пользователи', '-'*5)
print(blocked_users.info())
display(blocked_users.head(5))

print('-'*5, 'Не заблокированные пользователи', '-'*5)
print(non_blocked_users.info())
display(non_blocked_users.head(5))
----- Заблокированные пользователи -----
<class 'pandas.core.frame.DataFrame'>
Index: 14 entries, 13 to 196
Data columns (total 2 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   ID пользователя   14 non-null     object
 1   Имя пользователя  14 non-null     object
dtypes: object(2)
memory usage: 336.0+ bytes
None
ID пользователя Имя пользователя
13 0b9ec6fd-10d5-4436-8748-3bfe58677e89 Степанова О.Г.
52 3f7cd252-a4db-4774-ad74-6026668d4b07 Куликова Р.М.
54 421d676f-9536-4046-83aa-9b39cf666e30 Морозов А.А.
55 42e0089a-6687-4c36-b291-e50814cd15ed Смирнова Л.Д.
65 4842d040-4327-4245-b837-34561fb30273 Сорокин М.С.
----- Не заблокированные пользователи -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 216 entries, 0 to 215
Data columns (total 2 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   ID пользователя   216 non-null    object
 1   Имя пользователя  216 non-null    object
dtypes: object(2)
memory usage: 3.5+ KB
None
ID пользователя Имя пользователя
0 00000000-0000-0000-0000-000000000002 Бухгалтерские сервисы
1 00000000-0000-0000-0000-000000000003 ИТ-сервисы
2 00000000-0000-0000-0000-000000000004 Сайт компании
3 00000000-0000-0000-0000-000000000005 Робот службы безопасности
4 00000000-0000-0000-0000-000000000006 Робот финансовой службы
In [35]:
# Правила с заблокированными пользователями
_rules_with_blocked_users = rules_not_contextual_roles[
    rules_not_contextual_roles['ID пользователя'].isin(blocked_users['ID пользователя'])
]['ID правила доступа'].drop_duplicates()
rules_with_blocked_users = rules_with_users[rules_with_users['ID правила доступа'].isin(_rules_with_blocked_users)].drop_duplicates()
rules_with_blocked_users.to_csv('clusters/rules_with_blocked_users.csv')

# Правила с не заблокированными пользователями
_rules_with_non_blocked_users = rules_not_contextual_roles[
    rules_not_contextual_roles['ID пользователя'].isin(non_blocked_users['ID пользователя'])
]['ID правила доступа'].drop_duplicates()
rules_with_non_blocked_users = rules_with_users[rules_with_users['ID правила доступа'].isin(_rules_with_non_blocked_users)].drop_duplicates()
rules_with_non_blocked_users.to_csv('clusters/rules_with_non_blocked_users.csv')

print('-'*5, 'Правила с заблокированными пользователями', '-'*5)
print(rules_with_blocked_users.info())
display(rules_with_blocked_users.head(5))
print()

print('-'*5, 'Правила с не заблокированными пользователями', '-'*5)
print(rules_with_non_blocked_users.info())
display(rules_with_non_blocked_users.head(5))
----- Правила с заблокированными пользователями -----
<class 'pandas.core.frame.DataFrame'>
Index: 29 entries, 7 to 99
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        29 non-null     object
 1   Название правила доступа  29 non-null     object
 2   Правило отключено         29 non-null     bool  
dtypes: bool(1), object(2)
memory usage: 725.0+ bytes
None
ID правила доступа Название правила доступа Правило отключено
7 20336af0-1547-4441-b701-abb37eb7e80a Правило 26 False
9 2882e956-a847-4425-91eb-2a22860a766e Правило 86 False
10 2927ff14-1eb4-4c8d-8541-822547b8aa18 Правило 7 False
14 30b2b26e-1a46-4a60-addb-451eca6ce528 Правило 6 True
16 35d0ca67-430d-4101-866c-1425472896b1 Правило 54 False
----- Правила с не заблокированными пользователями -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 102 entries, 0 to 101
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        102 non-null    object
 1   Название правила доступа  102 non-null    object
 2   Правило отключено         102 non-null    bool  
dtypes: bool(1), object(2)
memory usage: 1.8+ KB
None
ID правила доступа Название правила доступа Правило отключено
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False
1 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False
2 09c45d7d-ee39-4e35-b47b-5b40edfa20bf Правило 184 False
3 131ea06e-e001-4cec-a0f8-b31d29bd57d6 Правило 20 False
4 13d02e38-aa00-4782-9770-bca53a6838b2 Правило 22 False

Правила с сотрудниками без групповых ролей¶

In [37]:
# Предварительный список правил с сотрудниками без групповых ролей
_rules_with_users_without_roles = rules_not_contextual_roles[
    rules_not_contextual_roles['Тип роли'] == 1 # Тип роли Сотрудник
].sort_values(['ID правила доступа', 'ID роли']).drop(['ID пользователя'], axis=1).drop_duplicates()

# Правила с сотрудниками без групповых ролей
rules_with_users_without_roles = pd.merge(_rules_with_users_without_roles['ID правила доступа'].drop_duplicates(), 
                                          rules_data[['ID правила доступа', 'Название правила доступа', 'Правило отключено']], 
                                          on='ID правила доступа', how='inner')
rules_with_users_without_roles.to_csv('clusters/rules_with_users_without_roles.csv')

# Пользователи без групповых ролей в правилах
roles_with_users_without_roles = pd.merge(_rules_with_users_without_roles[['ID роли', 'Тип роли']].drop_duplicates(), 
                                          roles_name[['ID роли', 'Название роли']], 
                                          on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]
roles_with_users_without_roles.to_csv('clusters/roles_with_users_without_roles.csv')

print('-'*5, 'Правила с сотрудниками без групповых ролей', '-'*5)
print(rules_with_users_without_roles.info())
display(rules_with_users_without_roles.head(5))
print()

print('-'*5, 'Пользователи без групповых ролей в правилах', '-'*5)
print(roles_with_users_without_roles.info())
display(roles_with_users_without_roles.head(5))
----- Правила с сотрудниками без групповых ролей -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 63 entries, 0 to 62
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        63 non-null     object
 1   Название правила доступа  63 non-null     object
 2   Правило отключено         63 non-null     bool  
dtypes: bool(1), object(2)
memory usage: 1.2+ KB
None
ID правила доступа Название правила доступа Правило отключено
0 09c45d7d-ee39-4e35-b47b-5b40edfa20bf Правило 184 False
1 131ea06e-e001-4cec-a0f8-b31d29bd57d6 Правило 20 False
2 13d02e38-aa00-4782-9770-bca53a6838b2 Правило 22 False
3 17b1b391-9abc-4f8c-9fd3-9e62bee4790d Правило 103 False
4 17c8a168-87ff-42ab-a499-a8af288649cf Правило 142 False
----- Пользователи без групповых ролей в правилах -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 65 entries, 0 to 64
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        65 non-null     object
 1   Название роли  65 non-null     object
 2   Тип роли       65 non-null     int64 
dtypes: int64(1), object(2)
memory usage: 1.7+ KB
None
ID роли Название роли Тип роли
0 71a48819-fca5-4d4d-a9b9-0ca13e41b63f Михайлов Д.Г. 1
1 8d0dc4c3-be5b-4294-82cf-9422c7c00eae Титов Д.Д. 1
2 eb532d6a-5ffa-4d26-83c6-af0912b79e27 Соловьёва Р.Д. 1
3 f1e9bbca-03a2-4d2e-939f-4573d680d245 Морозов А.А. 1
4 57ee420c-1548-42b3-b8b6-f3cbc9b65ce1 Комарова Т.В. 1

Правила с пользователем System¶

In [39]:
# Предварительный список правил с пользователем System
_rules_with_system = rules_not_contextual_roles[
    rules_not_contextual_roles['ID пользователя'] == '11111111-1111-1111-1111-111111111111' # Пользователь System
].sort_values(['ID правила доступа', 'ID роли']).drop(['ID пользователя'], axis=1).drop_duplicates()

# Правила с пользователем System
rules_with_system = pd.merge(_rules_with_system['ID правила доступа'].drop_duplicates(), 
                             rules_data[['ID правила доступа', 'Название правила доступа', 'Правило отключено']], 
                             on='ID правила доступа', how='inner')
rules_with_system.to_csv('clusters/rules_with_system.csv')

# Роли с пользователем System
roles_with_system = pd.merge(_rules_with_system[['ID роли', 'Тип роли']].drop_duplicates(), 
                             roles_name[['ID роли', 'Название роли']], 
                             on='ID роли', how='left')[['ID роли', 'Название роли', 'Тип роли']]
roles_with_system.to_csv('clusters/roles_with_users_without_roles.csv')

print('-'*5, 'Правила с пользователем System', '-'*5)
print(rules_with_system.info())
display(rules_with_system.head(5))
print()

print('-'*5, 'Роли с пользователем System', '-'*5)
print(roles_with_system.info())
display(roles_with_system.head(5))
----- Правила с пользователем System -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 0 entries
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        0 non-null      object
 1   Название правила доступа  0 non-null      object
 2   Правило отключено         0 non-null      bool  
dtypes: bool(1), object(2)
memory usage: 132.0+ bytes
None
ID правила доступа Название правила доступа Правило отключено
----- Роли с пользователем System -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 0 entries
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        0 non-null      object
 1   Название роли  0 non-null      object
 2   Тип роли       0 non-null      int64 
dtypes: int64(1), object(2)
memory usage: 132.0+ bytes
None
ID роли Название роли Тип роли

Правила с системными ролями¶

In [41]:
rules_not_contextual_roles
Out[41]:
ID правила доступа ID роли ID пользователя Тип роли Правило отключено
0 20336af0-1547-4441-b701-abb37eb7e80a 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 80e5677f-e1d6-4ae1-ad2f-3d56ac543394 1 False
1 17c8a168-87ff-42ab-a499-a8af288649cf 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 6de6127b-f01b-4f2e-a9d8-1b8f53092e91 1 False
2 ed9ab1be-8faa-4f18-8fc8-1efc5402342b e96d002f-ee0f-461a-b831-561ff8b457e3 8d0dc4c3-be5b-4294-82cf-9422c7c00eae 2 True
3 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b 776d348c-5e78-45f6-b87d-6f1fbe205bbe 0 False
4 5286e47f-9078-49a9-b53d-7a832f1d4c36 fb2f72a0-002b-41f4-b61f-2a9a8660f24b e932ad1c-5331-4dfd-82b0-b5f45ca45c21 0 False
… … … … … …
3650 35d0ca67-430d-4101-866c-1425472896b1 0eda49ad-18db-4d8f-bbfc-5239b3f39252 290b018c-cfc2-4bca-aad0-0b117b3a2a19 0 False
3651 6e7ba467-4b8f-4628-a007-cfdb2b18c17a c4ddb00f-7aae-4a49-b468-9af017ed1100 eaa562e4-bdf3-4355-aa74-54060f2a8ec5 2 False
3652 83bd2279-20e7-440a-ab8a-f6b26cede17c 6f9f1412-d3a6-4be8-8789-5d542b896fa8 6f9f1412-d3a6-4be8-8789-5d542b896fa8 1 False
3653 56fb5b4b-8bcc-4287-84ac-26af690185c3 2bddbdfa-b91b-4ca5-8726-92e6a253f504 2bddbdfa-b91b-4ca5-8726-92e6a253f504 1 False
3654 862822e0-164e-426e-83fc-07f3af78f110 39c44b9b-46bf-4d0a-ba81-6b8084a396ce 39c44b9b-46bf-4d0a-ba81-6b8084a396ce 1 False

3655 rows × 5 columns

In [42]:
# Предварительный список правил с системными пользователями
'''
_rules_with_systems_roles = rules_not_contextual_roles[rules_not_contextual_roles['ID пользователя'].isin([
    #'11111111-1111-1111-1111-111111111111', #'System'
    '00000000-0000-0000-0000-000000000002', # 'Бухгалтерские сервисы'
    '00000000-0000-0000-0000-000000000003', # 'ИТ-сервисы'
    '00000000-0000-0000-0000-000000000004', # 'Сайт компании'
    '00000000-0000-0000-0000-000000000005', # 'Робот службы безопасности'
    '00000000-0000-0000-0000-000000000006', # 'Робот финансовой службы'
    '00000000-0000-0000-0000-000000000007'  # 'Юридические сервисы'
])].sort_values([
    'ID правила доступа',
    'ID роли'
]).drop(['ID пользователя', 
         'Должность пользователя', 
         'Уровень доступа пользователя', 
         'Тип учетной записи  пользователя', 
         'Блокировка учетной записи пользователя'
], axis=1).drop_duplicates()
'''
_rules_with_systems_roles = rules_not_contextual_roles[rules_not_contextual_roles['ID пользователя'].isin([
    #'11111111-1111-1111-1111-111111111111', #'System'
    '00000000-0000-0000-0000-000000000002', # 'Бухгалтерские сервисы'
    '00000000-0000-0000-0000-000000000003', # 'ИТ-сервисы'
    '00000000-0000-0000-0000-000000000004', # 'Сайт компании'
    '00000000-0000-0000-0000-000000000005', # 'Робот службы безопасности'
    '00000000-0000-0000-0000-000000000006', # 'Робот финансовой службы'
    '00000000-0000-0000-0000-000000000007'  # 'Юридические сервисы'
])].sort_values([
    'ID правила доступа',
    'ID роли'
]).drop(['ID пользователя'
], axis=1).drop_duplicates()

# Правила с системными пользователями
rules_with_systems_roles = pd.merge(
    _rules_with_systems_roles['ID правила доступа'].drop_duplicates(), 
    rules_data[['ID правила доступа','Название правила доступа','Правило отключено']],
    on='ID правила доступа', how='inner')
rules_with_systems_roles.to_csv('clusters/rules_with_system.csv')

# Роли с системными пользователями в правилах
roles_with_systems_roles = pd.merge(
    _rules_with_systems_roles[['ID роли','Тип роли']].drop_duplicates(), 
    role_name[['ID роли','Название роли']], 
    on='ID роли', how='left'
)[['ID роли','Название роли','Тип роли']]
roles_with_systems_roles.to_csv('clusters/roles_with_system.csv')

print('-'*5, 'Правила с системными пользователями', '-'*5)
print(rules_with_systems_roles.info())
display(rules_with_systems_roles.head(5))
print()

print('-'*5, 'Роли с системными пользователями в правилах','-'*5)
print(roles_with_systems_roles.info())
display(roles_with_systems_roles.head(5))
----- Правила с системными пользователями -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        4 non-null      object
 1   Название правила доступа  4 non-null      object
 2   Правило отключено         4 non-null      bool  
dtypes: bool(1), object(2)
memory usage: 200.0+ bytes
None
ID правила доступа Название правила доступа Правило отключено
0 5f00b5e3-060e-4f76-923b-9c5cee5fb1a2 Правило 30 False
1 62efd89f-4495-4042-bc08-5ba4fc608d05 Правило 12 False
2 635e701d-f2bd-4616-8994-db1206c5f882 Правило 160 False
3 b2322015-2883-460c-be26-99803aa581e3 Правило 53 False
----- Роли с системными пользователями в правилах -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        3 non-null      object
 1   Название роли  3 non-null      object
 2   Тип роли       3 non-null      int64 
dtypes: int64(1), object(2)
memory usage: 204.0+ bytes
None
ID роли Название роли Тип роли
0 00000000-0000-0000-0000-000000000002 Бухгалтерские сервисы 1
1 00000000-0000-0000-0000-000000000004 Сайт компании 1
2 00000000-0000-0000-0000-000000000005 Робот службы безопасности 1

Правила с администраторами¶

In [44]:
# Предварительный список правил с администраторами
'''
_rules_with_admins = rules_not_contextual_roles[
    (rules_not_contextual_roles['ID пользователя'].isin(['00000000-0000-0000-0000-000000000008'])) # Статическая роль 'Сотрудники с правами Администратора
    | (rules_not_contextual_roles['Уровень доступа пользователя']== 1) # Административный уровень доступа
].sort_values(['ID правила доступа','ID роли']).drop([
    'ID пользователя', 'Доложность пользователя', 
    'Уровень доступа пользователя', 'Тип учетной записи пользователя', 
    'Блокировка учетной записи пользователя'
], axis=1).drop_duplicates
'''
_rules_with_admins = rules_not_contextual_roles[
    (rules_not_contextual_roles['ID пользователя'] == '00000000-0000-0000-0000-000000000008') # Статическая роль 'Сотрудники с правами Администратора
    | (
        rules_not_contextual_roles['ID пользователя'].isin(
            user_data[user_data['Уровень доступа пользователя'] == 1]['ID пользователя']
        )
    ) # Административный уровень доступа
].sort_values(['ID правила доступа','ID роли']).drop([
    'ID пользователя'], axis=1).drop_duplicates()

# Правила с администраторами
rules_with_admins = pd.merge(_rules_with_admins['ID правила доступа'].drop_duplicates(), 
                             rules_data[['ID правила доступа', 
                                         'Название правила доступа', 
                                         'Правило отключено']], on='ID правила доступа', how='inner')
rules_with_admins.to_csv('clusters/rules_with_admins.csv')

# Роли с администраторами
roles_with_admins = pd.merge(_rules_with_admins[['ID роли','Тип роли']].drop_duplicates(), 
                             role_name[['ID роли','Название роли']], 
                             on='ID роли', how='left')[['ID роли','Название роли','Тип роли']]
roles_with_admins.to_csv('clusters/roles_with_admins.csv')

print('-'*5, 'Правила с администраторами', '-'*5)
print(rules_with_admins.info())
display(rules_with_admins.head(5))
print()

print('-'*5, 'Роли с администраторами в правилах', '-'*5)
print(roles_with_admins.info())
display(roles_with_admins.head(5))
----- Правила с администраторами -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69 entries, 0 to 68
Data columns (total 3 columns):
 #   Column                    Non-Null Count  Dtype 
---  ------                    --------------  ----- 
 0   ID правила доступа        69 non-null     object
 1   Название правила доступа  69 non-null     object
 2   Правило отключено         69 non-null     bool  
dtypes: bool(1), object(2)
memory usage: 1.3+ KB
None
ID правила доступа Название правила доступа Правило отключено
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False
1 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False
2 09c45d7d-ee39-4e35-b47b-5b40edfa20bf Правило 184 False
3 131ea06e-e001-4cec-a0f8-b31d29bd57d6 Правило 20 False
4 13d02e38-aa00-4782-9770-bca53a6838b2 Правило 22 False
----- Роли с администраторами в правилах -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 64 entries, 0 to 63
Data columns (total 3 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   ID роли        64 non-null     object
 1   Название роли  64 non-null     object
 2   Тип роли       64 non-null     int64 
dtypes: int64(1), object(2)
memory usage: 1.6+ KB
None
ID роли Название роли Тип роли
0 49d7a40b-b8a2-4e51-ab99-febf59a885b6 Юридический отдел 2
1 27a6ba8d-4cc5-464e-a1d9-d30daf643391 Отдел продаж 2
2 71a48819-fca5-4d4d-a9b9-0ca13e41b63f Михайлов Д.Г. 1
3 8d0dc4c3-be5b-4294-82cf-9422c7c00eae Титов Д.Д. 1
4 d1c293a6-21aa-4c45-8e77-ceb8f6fc726a Руководство 2

Объединение данных о результатах анализа правил¶

In [46]:
# Данные о правилах
result_rules = rules_data[['ID правила доступа','Название правила доступа','Правило отключено']].drop_duplicates()
result_rules['РПД'] = np.where(result_rules['ID правила доступа'].isin(rules_data[rules_data['РПД'] == True]['ID правила доступа']), True, False)
result_rules['Типы условий'] = np.where(result_rules['ID правила доступа'].isin(rules_data[rules_data['Типы условий'] == True]['ID правила доступа']), True, False)
# Данные о ролях в правилах
result_rules['Контекстные роли'] = np.where(result_rules['ID правила доступа'].isin(rules_roles[rules_roles['Тип роли'] == 4]['ID правила доступа']), True, False)
result_rules['Роли с пользователями'] = np.where(result_rules['ID правила доступа'].isin(rules_with_users['ID правила доступа']), True, False)
result_rules['Роли без пользователей'] = np.where(result_rules['ID правила доступа'].isin(rules_without_users['ID правила доступа']), True, False)
result_rules['Роли с не заблокированными пользователями'] = np.where(result_rules['ID правила доступа'].isin(rules_with_non_blocked_users['ID правила доступа']), True, False)
result_rules['Роли с заблокированными пользователями'] = np.where(result_rules['ID правила доступа'].isin(rules_with_blocked_users['ID правила доступа']), True, False)
result_rules['Пользователи без групповых ролей'] = np.where(result_rules['ID правила доступа'].isin(rules_with_users_without_roles['ID правила доступа']), True, False)
result_rules['Роли с System'] = np.where(result_rules['ID правила доступа'].isin(rules_with_system['ID правила доступа']), True, False)
result_rules['Роли с системными пользователям'] = np.where(result_rules['ID правила доступа'].isin(rules_with_systems_roles['ID правила доступа']), True, False)
result_rules['Роли с администраторами'] = np.where(result_rules['ID правила доступа'].isin(rules_with_admins['ID правила доступа']), True, False)
# Данные о разрешениях
result_rules['Чтение карточки'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Чтение карточки'] == True]['ID правила доступа']), True, False)
result_rules['Создание карточки'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Создание карточки'] == True]['ID правила доступа']), True, False)
result_rules['Редактирование карточки'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Редактирование карточки'] == True]['ID правила доступа']), True, False)
result_rules['Удаление карточки'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Удаление карточки'] == True]['ID правила доступа']), True, False)
result_rules['Добавление файлов'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Добавление файлов'] == True]['ID правила доступа']), True, False)
result_rules['Редактирование файлов'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Редактирование файлов'] == True]['ID правила доступа']), True, False)
result_rules['Удаление всех файлов'] = np.where(result_rules['ID правила доступа'].isin(KrPermissions[KrPermissions['Удаление всех файлов'] == True]['ID правила доступа']), True, False)

print('-'*5,'Результаты анализа правил','-'*5)
print(result_rules.info())
display(result_rules.head(5))
----- Результаты анализа правил -----
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 187 entries, 0 to 186
Data columns (total 21 columns):
 #   Column                                     Non-Null Count  Dtype 
---  ------                                     --------------  ----- 
 0   ID правила доступа                         187 non-null    object
 1   Название правила доступа                   187 non-null    object
 2   Правило отключено                          187 non-null    bool  
 3   РПД                                        187 non-null    bool  
 4   Типы условий                               187 non-null    bool  
 5   Контекстные роли                           187 non-null    bool  
 6   Роли с пользователями                      187 non-null    bool  
 7   Роли без пользователей                     187 non-null    bool  
 8   Роли с не заблокированными пользователями  187 non-null    bool  
 9   Роли с заблокированными пользователями     187 non-null    bool  
 10  Пользователи без групповых ролей           187 non-null    bool  
 11  Роли с System                              187 non-null    bool  
 12  Роли с системными пользователям            187 non-null    bool  
 13  Роли с администраторами                    187 non-null    bool  
 14  Чтение карточки                            187 non-null    bool  
 15  Создание карточки                          187 non-null    bool  
 16  Редактирование карточки                    187 non-null    bool  
 17  Удаление карточки                          187 non-null    bool  
 18  Добавление файлов                          187 non-null    bool  
 19  Редактирование файлов                      187 non-null    bool  
 20  Удаление всех файлов                       187 non-null    bool  
dtypes: bool(19), object(2)
memory usage: 6.5+ KB
None
ID правила доступа Название правила доступа Правило отключено РПД Типы условий Контекстные роли Роли с пользователями Роли без пользователей Роли с не заблокированными пользователями Роли с заблокированными пользователями … Роли с System Роли с системными пользователям Роли с администраторами Чтение карточки Создание карточки Редактирование карточки Удаление карточки Добавление файлов Редактирование файлов Удаление всех файлов
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False True False False True False True False … False False True True True False False True True False
1 0359fea5-f9d6-4911-acbe-70f82c858418 Правило 143 True False False False False False False False … False False False True False False True False False False
2 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False False False False True False True False … False False True True True True True True False False
3 05bd596d-c6ad-474b-80db-fdbecab66f21 Правило 124 True False False False False False False False … False False False False True True True True False False
4 07cc452b-48c4-4176-b13d-ab576ae7afdc Правило 67 False False False False False False False False … False False False True False True False False False False

5 rows × 21 columns

Кластеризация правил¶

In [48]:
# Кластеры правил и рекомендации
result_rules['Кластеры'] = ''
result_rules['Рекомендации'] = ''

# Все роли пустые
mask = ((result_rules['Роли с пользователями'] == False)
    & (result_rules['Роли без пользователей'] == True)
    | ( (result_rules['Роли с не заблокированными пользователями'] == False)
    & (result_rules['Роли с заблокированными пользователями'] == True))
    & (result_rules['Кластеры'] == ''))
result_rules.loc[mask, 'Кластеры'] = 'Все роли пустые. '
result_rules.loc[mask, 'Рекомендации'] = 'Удалить правила и роли внутри них. '

# Есть пустые роли
mask = ((result_rules['Роли с пользователями'] == True)
    & (result_rules['Роли без пользователей'] == True)
    | ( (result_rules['Роли с не заблокированными пользователями'] == True)
    & (result_rules['Роли с заблокированными пользователями'] == True)))
result_rules.loc[mask, 'Кластеры'] = 'Пустые роли. '
result_rules.loc[mask, 'Рекомендации'] = 'Проверить правила и роли внутри них. '

# Иднивидуальные роли
mask = (result_rules['Пользователи без групповых ролей'] == True)
result_rules.loc[mask, 'Кластеры'] += 'Индивидуальные роли. '
result_rules.loc[mask, 'Рекомендации'] += 'Использовать групповые роли вместо иднивидуальных'

# Контекстные роли
mask = (result_rules['Контекстные роли'] == True)
result_rules.loc[mask, 'Кластеры'] += 'Контекстные роли. '
result_rules.loc[mask, 'Рекомендации'] += 'Контекстные роли заменить на групповые роли и типы условий. '

# Системные роли
mask = ((result_rules['Роли с системными пользователям'] == True))
result_rules.loc[mask, 'Кластеры'] += 'Системные роли. '
result_rules.loc[mask, 'Рекомендации'] += 'Сверить права системных ролей с их ТЗ. '

# Административные права
mask = ((result_rules['Роли с System'] == True)
    | (result_rules['Роли с администраторами'] == True))
result_rules.loc[mask, 'Кластеры'] += 'Административные права. '
result_rules.loc[mask, 'Рекомендации'] += 'Особое внимание на список администраторов. '

# Полные права на модификацию документов
mask = ((result_rules['Редактирование карточки'] == True)
    & (result_rules['Удаление карточки'] == True)
    & (result_rules['Добавление файлов'] == True)
    & (result_rules['Редактирование файлов'] == True)
    & (result_rules['Удаление всех файлов'] == True))
result_rules.loc[mask, 'Кластеры'] += 'Полные права на модификацию документов. '
result_rules.loc[mask, 'Рекомендации'] += 'Проверить риск возможности подлога документов. '

# Права на чтение
mask = ((result_rules['Чтение карточки'] == True))
result_rules.loc[mask, 'Кластеры'] += 'Права на чтение. '
result_rules.loc[mask, 'Рекомендации'] += 'Сверить права с бизнес-требованиями на доступ к документам. '

# Права на создание
mask = ((result_rules['Создание карточки'] == True))
result_rules.loc[mask, 'Кластеры'] += 'Права на создание. '
result_rules.loc[mask, 'Рекомендации'] += ''

result_rules.to_csv('clusters/result_rules.csv', sep=';', encoding='utf-8-sig')
result_rules.head()
Out[48]:
ID правила доступа Название правила доступа Правило отключено РПД Типы условий Контекстные роли Роли с пользователями Роли без пользователей Роли с не заблокированными пользователями Роли с заблокированными пользователями … Роли с администраторами Чтение карточки Создание карточки Редактирование карточки Удаление карточки Добавление файлов Редактирование файлов Удаление всех файлов Кластеры Рекомендации
0 0156312e-890f-49e3-8c5d-d8df16376bd4 Правило 38 False True False False True False True False … True True True False False True True False Административные права. Права на чтение. Права… Особое внимание на список администраторов. Све…
1 0359fea5-f9d6-4911-acbe-70f82c858418 Правило 143 True False False False False False False False … False True False False True False False False Права на чтение. Сверить права с бизнес-требованиями на доступ …
2 051b8ae8-cefe-4327-9511-777515747775 Правило 47 False False False False True False True False … True True True True True True False False Административные права. Права на чтение. Права… Особое внимание на список администраторов. Све…
3 05bd596d-c6ad-474b-80db-fdbecab66f21 Правило 124 True False False False False False False False … False False True True True True False False Права на создание.
4 07cc452b-48c4-4176-b13d-ab576ae7afdc Правило 67 False False False False False False False False … False True False True False False False False Права на чтение. Сверить права с бизнес-требованиями на доступ …

5 rows × 23 columns

Python sql анализ информационная система информация корпоративная информационная система модель предоставления прав практика

Предыдущая статьяИнтерпретация кластерного анализа модели предоставления разрешений в TessaСледующая статья Общая концепция анализа модели предоставления прав в информационной системе

Рубрики

Метки

abc abcd AI-Ready платформа Data Lakehouse ELT excel ms sql pandas PostgreSQL Python sql tessa VBA xyz анализ виртуальный помощник гибридное хранилище данных данные знания информационная система информация искусственный интеллект кластерный анализ комбинаторика компетенции корпоративная информационная система маркетинг математика медальон-архитектура модель предоставления прав мудрость о проекте оптимизация ошибка практика программное обеспечение пэст ролевая модель теория теория вероятностей тесса тест юмор языки программирования

Политика конфиденциальности

Продолжая использовать данный сайт вы подтверждаете свое согласие с условиями его политики конфиденциальности. Подробнее…




Администрация и владельцы данного информационного ресурса не несут ответственности за возможные последствия, связанные с использованием информации, размещенной на нем.


Все права защищены. При копировании материалов сайта обязательно указывать ссылку на © Microsegment.ru (2020-2026)