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

Анализ предоставленных разрешений в Tessa

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

По мере роста информационной системы (далее ИС) и количества ее пользователей в ней ощутимо увеличивается количество выданных разрешений. Усложнение ролевой модели, увеличение количества условий и объектов в ИС усложняет предоставление пользователям уникальных разрешений. Поэтому, в общей концепции анализа модели предоставления прав в ИС важную роль играет анализ предоставленных разрешений. Проведение этого анализа путем простой группировки правил и сравнения, например, косинусных расстояний векторов предоставленных разрешений, практически лишено смысла. Эти методы не дают репрезентативного результата, а косинусный анализ еще и сопряжен с высокой вычислительной нагрузкой, даже при использовании методов CountVectorizer и NearestNeighbors библиотеки sklearn. Однако, анализ возможен путем группировки сравниваемых правил по исходным правилами, пользовательским ролям, типам и состояниям карточек. Далее представлен подобный метод анализа на примере предоставленных разрешений в Tessa.

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

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

-- Все правила доступа с русским переводом параметров
SELECT  kp.ID AS [ID правила доступа],
        kp.Caption AS [Название правила доступа],
        kp.IsDisabled AS [Правило отключено],
        kp.IsRequired AS [Всегда проверять правило],
        kp.IsExtended AS [РПД],
        kp.Conditions LIKE '%ConditionTypeID%' THEN 1 ELSE 0 END AS [Типы условий],
        -- Разрешения из правил доступа
        kp.CanCreateCard AS [Создание карточки],
        kp.CanReadCard AS [Чтение карточки],
        kp.CanEditCard AS [Редактирование карточки],
        kp.CanEditFiles AS [Редактирование файлов],
        kp.CanAddFiles AS [Добавление файлов],
        kp.CanEditRoute AS [Редактирование маршрута],
        kp.CanDeleteCard AS [Удаление карточки],
        kp.CanStartProcess AS [Инициация типового процесса отправки задач],
        kp.CanEditNumber AS [Ручное редактирование номера],
        kp.CanCreateResolutions AS [Создание резолюций],
        kp.CanDeleteFiles AS [Удаление всех файлов],
        kp.CanEditOwnFiles AS [Редактирование собственных файлов].
        kp.CanDeleteownFiles AS [Удаление собственных файлов],
        kp.CansignFiles AS [Подписание файлов],
        kp.CanAddTopics AS [Создание обсуждений].
        kp.CanSuperModeratorMode AS [Права супермодератора],
        kp.CanSubscribeForNotifications AS [Подписка на уведомления],
        kp.CanCreateTemplateAndCopy AS [Создание шаблона и копирование],
        kp.CanSkipStages AS [Пропуск этапов],
        kp.CanFullRecalcRoute AS [Полный пересчет маршрута].
        kp.CanEditMyMessages AS [Редактирование своих сообщений],
        kp.CanEditAllMessages AS [Редактирование всех сообщений],
        kp.CanReadAllTopics AS [Чтение обсуждений],
        kp.CanReadAndSendMessageInAllTopics 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 [Логин пользователя],
        pr.Blocked AS [Блокировка учетной записи пользователя], 
        r.ID AS [ID роли], 
        r.Name AS [Название роли], 
        r.TypeID AS [Тип роли]
FROM Roles (NOLOCK)r
INNER JOIN RoleUsers (NOLOCK) ru ON ru.ID = r.ID
INNER 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 [7]:
import pandas as pd
import numpy as np

# Работа с подстроками
import re
# Работа со временем
from datetime import datetime
import pytz

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

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

print(kr_permissions.info())
kr_permissions.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 209 entries, 0 to 208
Data columns (total 30 columns):
 #   Column                                      Non-Null Count  Dtype 
---  ------                                      --------------  ----- 
 0   ID правила доступа                          209 non-null    object
 1   Название правила доступа                    209 non-null    object
 2   Правило отключено                           209 non-null    bool  
 3   Всегда проверять правило                    209 non-null    bool  
 4   РПД                                         209 non-null    bool  
 5   Типы условий                                209 non-null    bool  
 6   Создание карточки                           209 non-null    bool  
 7   Чтение карточки                             209 non-null    bool  
 8   Редактирование карточки                     209 non-null    bool  
 9   Удаление карточки                           209 non-null    bool  
 10  Добавление файлов                           209 non-null    bool  
 11  Редактирование собственных файлов           209 non-null    bool  
 12  Редактирование файлов                       209 non-null    bool  
 13  Удаление собственных файлов                 209 non-null    bool  
 14  Удаление всех файлов                        209 non-null    bool  
 15  Инициация типового процесса отправки задач  209 non-null    bool  
 16  Редактирование маршрута                     209 non-null    bool  
 17  Пропуск этапов                              209 non-null    bool  
 18  Полный пересчет маршрута                    209 non-null    bool  
 19  Ручное редактирование номера                209 non-null    bool  
 20  Создание резолюций                          209 non-null    bool  
 21  Подписание файлов                           209 non-null    bool  
 22  Создание обсуждений                         209 non-null    bool  
 23  Права супермодератора                       209 non-null    bool  
 24  Подписка на уведомления                     209 non-null    bool  
 25  Создание шаблона и копирование              209 non-null    bool  
 26  Редактирование своих сообщений              209 non-null    bool  
 27  Редактирование всех сообщений               209 non-null    bool  
 28  Чтение обсуждений                           209 non-null    bool  
 29  Чтение и отправка сообщений                 209 non-null    bool  
dtypes: bool(28), object(2)
memory usage: 9.1+ KB
None
Out[9]:
ID правила доступа Название правила доступа Правило отключено Всегда проверять правило РПД Типы условий Создание карточки Чтение карточки Редактирование карточки Удаление карточки … Создание резолюций Подписание файлов Создание обсуждений Права супермодератора Подписка на уведомления Создание шаблона и копирование Редактирование своих сообщений Редактирование всех сообщений Чтение обсуждений Чтение и отправка сообщений
0 9c3612f2-42ad-4161-aff5-e40ae544a0c5 Правило 0 True True False False True True False True … False False False False False False False False False False
1 edcc653c-f93d-4b92-8aea-1219d670afe8 Правило 1 False False False False True True True False … True False False True False False False False False False
2 48367274-4d95-49e9-a24a-ecef6ca99c4d Правило 2 True False False False True True True False … False True False False False False False False False False
3 3b05d9bf-1def-49fb-bf8a-356cdb638267 Правило 3 True False True False False True True False … False False False False False False False False False False
4 5533c7bb-854d-40a9-9882-9d01bdf9117b Правило 4 True True False False True True True False … False False False False False False False False False False

5 rows × 30 columns

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

print(kr_permission_roles.info())
kr_permission_roles.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 897 entries, 0 to 896
Data columns (total 3 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  897 non-null    object
 1   ID роли             897 non-null    object
 2   Название роли       897 non-null    object
dtypes: object(3)
memory usage: 21.2+ KB
None
Out[10]:
ID правила доступа ID роли Название роли
0 1512e0f2-fe6d-4e20-8b8b-1fbc0ae37ed3 6be734e0-7828-4eed-867d-b3964c07084a Куликов И.К.
1 3155720a-a0e1-414e-ad91-51355b943b9b ed65640c-0b9b-444c-a592-b2e8a3be09c0 Обработчик входящих документов
2 3155720a-a0e1-414e-ad91-51355b943b9b ed65640c-0b9b-444c-a592-b2e8a3be09c0 Обработчик входящих документов
3 3155720a-a0e1-414e-ad91-51355b943b9b ed65640c-0b9b-444c-a592-b2e8a3be09c0 Обработчик входящих документов
4 3155720a-a0e1-414e-ad91-51355b943b9b ed65640c-0b9b-444c-a592-b2e8a3be09c0 Обработчик входящих документов
In [11]:
# Данные из таблицы KrPermissionTypes, предварительно выгруженные из БД Tessa
kr_permission_types = pd.read_csv('files/KrPermissionTypes.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(kr_permission_types.info())
kr_permission_types.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 263 entries, 0 to 262
Data columns (total 3 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   ID правила доступа  263 non-null    object
 1   ID типа карточки    256 non-null    object
 2   Тип карточки        256 non-null    object
dtypes: object(3)
memory usage: 6.3+ KB
None
Out[11]:
ID правила доступа ID типа карточки Тип карточки
0 64c3bf3d-fa08-425c-93f1-9e3e73fa2d64 f747e984-9dad-4d04-93d8-0508ad1419f5 Служебная записка
1 be0f5a3e-d51c-45f7-b04a-32c0cbacc8f9 a82f9ccc-d953-4797-bb77-ecde7e224160 Дополнительное соглашение
2 08622304-d149-4100-90bb-cfc916322c68 ff3a9f22-41c9-4b92-a18f-6fc9ebbb26b7 Договор
3 8f2bd213-e68a-4c72-ada0-438455877fe8 6024cb6c-72eb-4f19-9b46-80e16d77eaf2 МЧД
4 5f64a5ac-0a18-4307-931f-310a6e5f8f8c 15f0faf3-ddaa-4cf6-b34c-ad6a5c4010d0 Исходящий
In [12]:
# Данные из таблицы KrPermissionStates, предварительно выгруженные из БД Tessa
kr_permission_states = pd.read_csv('files/KrPermissionStates.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(kr_permission_states.info())
kr_permission_states.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 241 entries, 0 to 240
Data columns (total 3 columns):
 #   Column                 Non-Null Count  Dtype 
---  ------                 --------------  ----- 
 0   ID правила доступа     241 non-null    object
 1   ID состояния карточки  220 non-null    object
 2   Состояние карточки     220 non-null    object
dtypes: object(3)
memory usage: 5.8+ KB
None
Out[12]:
ID правила доступа ID состояния карточки Состояние карточки
0 1fec9e9d-f71f-4a21-8ea5-782f9aa7d9cd a352a190-f4af-494a-b835-3b930fbe4651 Отмена
1 d8186975-fec2-48ae-bda0-460b1978016e a352a190-f4af-494a-b835-3b930fbe4651 Отмена
2 f8fda4a1-1f0a-4b06-a6fc-5a4a10c6311c d97f3b50-53cc-4c22-b7a0-a38c5589610c На обработке
3 08622304-d149-4100-90bb-cfc916322c68 1f528af1-84b9-4861-bc8c-88ed33ca09a1 Зарегистрирован
4 9a049833-96fe-4f6c-ace5-9d2dd7560f7e a352a190-f4af-494a-b835-3b930fbe4651 Отмена
In [13]:
# Данные из таблицы KrPermissionExtendedcard, предварительно выгруженные из БД Tessa
kr_permission_extended_card_rules = pd.read_csv('files/KrPermissionExtendedCardRules.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(kr_permission_extended_card_rules.info())
kr_permission_extended_card_rules.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[13]:
ID правила доступа РПД. Секция карточки РПД. Поле карточки РПД. Разрешение РПД. Разрешение (рус)
0 9c3612f2-42ad-4161-aff5-e40ae544a0c5 Document DocumentText Write Редактирование
1 edcc653c-f93d-4b92-8aea-1219d670afe8 GeneralInformation CreationDate DenyWrite Запрещено редактировать
2 48367274-4d95-49e9-a24a-ecef6ca99c4d EmployeeCard Salary Read Чтение
3 3b05d9bf-1def-49fb-bf8a-356cdb638267 ApprovalStage Comments Append Добавление комментариев
4 5533c7bb-854d-40a9-9882-9d01bdf9117b BasicData Subject DenyDelete Запрещено удалять
In [14]:
# Данные из таблицы RoleUsers, предварительно выгруженные из БД Tessa
role_users = pd.read_csv('files/RoleUsers.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(role_users.info())
role_users.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 456 entries, 0 to 455
Data columns (total 10 columns):
 #   Column                                  Non-Null Count  Dtype  
---  ------                                  --------------  -----  
 0   ID пользователя                         456 non-null    object 
 1   Имя пользователя                        456 non-null    object 
 2   Должность пользователя                  456 non-null    object 
 3   Уровень доступа пользователя            433 non-null    float64
 4   Тип учетной записи пользователя         446 non-null    float64
 5   Логин пользователя                      456 non-null    object 
 6   Блокировка учетной записи пользователя  341 non-null    object 
 7   ID роли                                 456 non-null    object 
 8   Название роли                           456 non-null    object 
 9   Тип роли                                456 non-null    int64  
dtypes: float64(2), int64(1), object(7)
memory usage: 35.8+ KB
None
Out[14]:
ID пользователя Имя пользователя Должность пользователя Уровень доступа пользователя Тип учетной записи пользователя Логин пользователя Блокировка учетной записи пользователя ID роли Название роли Тип роли
0 554afab6-1d5b-41aa-809b-32ae4398e6ec Алексеев Р.В. Начальник отдела 1.0 1.0 alekseevrv False a44ab062-f574-44fe-bf5c-714c67409ec4 Отдел кадров 2
1 0e0eaf55-9fb6-4e7c-8631-ee50c699973e Попова И.Б. Начальник отдела NaN 2.0 popovaib False a219a94f-b19a-49df-a73b-fbc3da990502 IT-отдел 2
2 7429bd03-3e7f-4800-b609-7e99d0934854 Воробьёва Д.Л. Начальник отдела 0.0 1.0 vorobeovadl True a5aa3f4f-ef3e-4486-a583-55632ce1fdec Отдел продаж 2
3 1293a828-e5b6-4101-b005-eb4db253db4e Сорокин М.Р. Менеджер проекта 0.0 1.0 sorokinmr NaN 18798bd5-7ad6-4fe0-946d-6a8dc3e7dc0f Отдел продаж 2
4 a619e660-b6bc-4964-acf7-d919953c35ea Волков А.В. Менеджер проекта 0.0 2.0 volkovav True 5a382a70-9280-44dc-bdc6-79b5682e52f2 Отдел продаж 2
In [15]:
# Данные из таблицы ContextRoles, предварительно выгруженные из БД Tessa
context_roles = pd.read_csv('files/ContextRoles.csv').drop('Unnamed: 0', axis=1)#, sep=';', encoding='utf-8-sig')

print(context_roles.info())
context_roles.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[15]:
ID роли Код SQL
0 5efb6cc8-3817-4250-b200-16c8f47637ec \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
1 ea1fabb9-76d4-412c-87c1-02ba1b2d4eae \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
2 1c75b493-3e5b-4231-a8f1-0344652b35a2 \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
3 1ce434a5-b048-47b8-b865-acfc9e32b3b3 \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …
4 bf7f2167-23a2-424c-95e9-6d64c9835e5d \nSELECT u.UserID, u.Name\nFROM Users u\nJOIN …

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

In [17]:
# Уникальные пользователи
user_data = role_users[[
    'ID пользователя', 
    'Имя пользователя'
]].dropna().drop_duplicates().sort_values('Имя пользователя').reset_index(drop=True)

print(user_data.info())
user_data.head(5)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 199 entries, 0 to 198
Data columns (total 2 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   ID пользователя   199 non-null    object
 1   Имя пользователя  199 non-null    object
dtypes: object(2)
memory usage: 3.2+ KB
None
Out[17]:
ID пользователя Имя пользователя
0 11111111-1111-1111-1111-111111111111 System
1 7c6ee0cb-21c5-4524-a2f4-962662b93bd0 Алексеев Л.Р.
2 69ffa31d-c876-4657-94f1-1190bc8d0e7e Алексеев Л.Р.
3 5c45994d-530c-4552-b365-9ef9381b99a9 Алексеев Р.В.
4 1de27c1e-ea4c-4e91-a1aa-9b92ef4f828d Алексеев Р.В.

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

In [19]:
# NEW
# Кластеризация правил по пользователям, типам и состояниям карточек
# с подсчетом количества совпадающих разрешений в правилах

# Итерационная переменная для подсчета 
# количества чанок сотрудников
n = 0
# Чанки пользователей
for u_index, u in user_data.iterrows():
    
    # Создание датафрейма сотрудника. 
    # Объединение данных о пользователях и ролях 
    # с ID правил доступа, где используются роли 
    df = pd.merge(
        role_users[role_users['ID пользователя'] == u['ID пользователя']].sort_values([
            'Имя пользователя', 
            'Название роли'
        ])[[
            'ID пользователя', 
            'Имя пользователя', 
            'ID роли', 
            'Название роли', 
            'Тип роли'
        ]], 
        kr_permission_roles[['ID роли', 'ID правила доступа']].sort_values('ID роли'), 
        on='ID роли', 
        how='inner'
    )
    # Выход из цикла, если датафрейм пустой
    if len(df) == 0: continue
    
    # Объединение данных о ролях из текущей чанки сотрудника
    # с данными о правилах, в которых есть эти роли
    df = pd.merge(
        df, 
        kr_permission_types, 
        on='ID правила доступа', 
        how='inner'
    )
    df = pd.merge(
        df, 
        kr_permission_states, 
        on='ID правила доступа', 
        how='inner'
    )
    df = pd.merge(
        df, 
        kr_permissions, 
        on='ID правила доступа', 
        how='inner'
    )
    # Выход из цикла, если датафрейм пустой
    if len(df) == 0: continue
    
    # Изменение порядка столбцов
    df = df.iloc[:,[
        0, 1, 2, 3, 4, 5, 10, 6, 7, 8, 9, 
        11, 12, 13, 14, 15, 16, 17, 18, 19, 
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 
        30, 31, 32, 33, 34, 35, 36, 37, 38 
    ]]

    # Приведение типа параметров разрешений с bool к int
    temp_df = df.iloc[:, 11:].astype('int8')
    df = pd.concat([
        df.iloc[:, :11], 
        temp_df
    ], axis=1)
    
    # Выделение параметров разрешений
    permissions_locs = df.iloc[:, 15:].columns.tolist()
    # Выделение всех параметров, кроме содержащих данные о пользователе
    locs = df.iloc[:, 2:].columns.tolist()
    # Выделение параметров по которым будет производиться объединение
    cross_locs = df.iloc[:, 7:10].columns.tolist()
    
    # Кросс-джойн через временный ключ
    df_locs = df[locs]
    df = df_locs.merge(df_locs, on=cross_locs, suffixes=('_x', '_y'))
    del df_locs
    
    # Удаление кросс-джойна с самим собой
    df = df[
        (df['ID правила доступа_x'] != df['ID правила доступа_y']) &
        (df['ID роли_x'] != df['ID роли_y'])
    ].copy()
    
    # Удаление обратных пар правило-роль
    df['x_pairs'] = df[['ID правила доступа_x', 'ID роли_x']].agg(frozenset, axis=1)
    df['y_pairs'] = df[['ID правила доступа_y', 'ID роли_y']].agg(frozenset, axis=1)
    df['xy_pairs'] = df[['x_pairs', 'y_pairs']].agg(frozenset, axis=1)
    df['yx_pairs'] = df[['y_pairs', 'x_pairs']].agg(frozenset, axis=1)
    df = df[
        ~df['xy_pairs'].duplicated() &
        ~df['yx_pairs'].duplicated()
    ].drop(columns=['x_pairs', 'y_pairs', 'xy_pairs', 'yx_pairs'])
    
    # Перемножение параметров разрешений
    for col in permissions_locs:
        df[f'{col}_prod'] = df[f'{col}_x'] * df[f'{col}_y']
        df = df.drop(columns=[f'{col}_x', f'{col}_y'])
    
    # Суммирование всех одинаковых разрешений
    df['Количество одинаковых разрешений'] = df[[f'{c}_prod' for c in permissions_locs]].sum(axis=1)
    # Сортировка объектов по количеству одинаковых разрешений
    df = df.sort_values('Количество одинаковых разрешений', ascending=False)
    # Удаление объектов без одинаковых разрешений
    df = df[df['Количество одинаковых разрешений'] > 0].reset_index(drop=True)
    # Выход из цикла, если датафрейм пустой
    if len(df) == 0: continue
    
    # Изменение порядка столбцов
    df = df.iloc[:,[
        5, 6, 7, 0, 1, 2, 3, 4, 8, 9, 
        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 
        30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 
        40, 41, 42, 43, 44, 45, 46, 47
    ]]
    
    # Корректировка названий полей датафрейма
    for col in df.columns:
        if '_x' in col:
            df.rename(columns={col: col.replace('_x', '')}, inplace=True)
        if '_y' in col:
            df.rename(columns={col: col.replace('_y', ' (сопоставлено)')}, inplace=True)
        if '_prod' in col:
            df.rename(columns={col: col.replace('_prod', '')}, inplace=True)
    
    # Вывод с демонстрацией всех полей датафрейма
    '''with pd.option_context('display.max_columns', None):
        print(df.info())
        display(df.head(5))'''
    
    # Вывод результатов кластеризации правил
    if 'df' in locals():
        if len(df) > 0:
            
            # Подсчет количества чанок сотрудников
            n += 1
            # Определение текущей даты и времени по Мск
            timestamp_now = datetime.now(pytz.timezone('Europe/Moscow')).strftime('%Y-%m-%d %H:%M:%S')
            # Очистка имен пользователей для безошибочного сохранения файлов 
            # с использованием их в названии
            safe_name = re.sub(r'[<>:"/\\|&*?]', '', u['Имя пользователя'])
            
            # Пошаговое сохранение данных об одинаковых разрешениях 
            # в отдельный файл для каждой чанки сотрудника
            df.to_excel(f'permissions_clusters/{safe_name}.xlsx', sheet_name='Sheet1')
            
            # Вывод результата обработки чанки соттрудника на экран
            print(f"{n}. {timestamp_now} у сотрудника {u['Имя пользователя']} \
обнаружено {len(df)} дублей с максимальным количеством \
одинаковых разрешений {df['Количество одинаковых разрешений'].max()}")
            # Вывод каждой чанки сотрудика в виде отдельной таблицы на экране
            # с демонстрацией всех полей датафрейма
            '''with pd.option_context('display.max_columns', None):
                #display(permissions_clusters.head(5))'''
            
            # Создание и наполнение итогового датафрейма
            # с основной информацией о результатах анализа разрешений
            if 'total' not in locals():
                total = pd.DataFrame(columns=['Дата и время', 'Сотрудники', 'Всего дублей', 'Максимум одинаковых разрешений'])
            total = pd.concat([
                total,
                pd.DataFrame({
                    'Дата и время':[timestamp_now], 
                    'Сотрудники':[u['Имя пользователя']], 
                    'Всего дублей':[len(df)], 
                    'Максимум одинаковых разрешений':[df['Количество одинаковых разрешений'].max()]
                })
            ], axis=0).reset_index(drop=True)
    
    # Принудительная остановка цикла для теста
    #if n > 5: break
    
1. 2026-05-29 14:28:54 у сотрудника Алексеев Л.Р. обнаружено 5 дублей с максимальным количеством одинаковых разрешений 5
2. 2026-05-29 14:28:55 у сотрудника Андреев Л.К. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 1
3. 2026-05-29 14:28:57 у сотрудника Виноградов Т.Г. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 2
4. 2026-05-29 14:28:57 у сотрудника Волков А.В. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 4
5. 2026-05-29 14:28:57 у сотрудника Герасимов С.А. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 2
6. 2026-05-29 14:28:58 у сотрудника Григорьева Т.Д. обнаружено 2 дублей с максимальным количеством одинаковых разрешений 7
7. 2026-05-29 14:28:58 у сотрудника Зайцев Р.С. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 4
8. 2026-05-29 14:29:00 у сотрудника Козлова К.Р. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 1
9. 2026-05-29 14:29:00 у сотрудника Кудрявцева С.М. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 6
10. 2026-05-29 14:29:01 у сотрудника Куликов Р.А. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 5
11. 2026-05-29 14:29:03 у сотрудника Новиков В.М. обнаружено 2 дублей с максимальным количеством одинаковых разрешений 5
12. 2026-05-29 14:29:03 у сотрудника Новиков Г.Л. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 4
13. 2026-05-29 14:29:04 у сотрудника Семёнов Г.Т. обнаружено 1 дублей с максимальным количеством одинаковых разрешений 6
14. 2026-05-29 14:29:05 у сотрудника Соловьёв А.Е. обнаружено 4 дублей с максимальным количеством одинаковых разрешений 3
15. 2026-05-29 14:29:07 у сотрудника Фёдорова А.Е. обнаружено 2 дублей с максимальным количеством одинаковых разрешений 5

Подведение итогов анализа существующих разрешений в Tessa¶

In [21]:
# Приведение строки к типу даты и времени и подсчет времени проведения анализа
total['Дата и время'] = pd.to_datetime(total['Дата и время'])
print('Продолжительность анализа', total['Дата и время'].max() - total['Дата и время'].min())
Продолжительность анализа 0 days 00:00:13
In [22]:
# Итоговые данные результатов анализа существующих разрешений в Tessa
print('Датафрейм с итоговыми данными результатов анализа существующих разрешений в Tessa:')
display(total)
Датафрейм с итоговыми данными результатов анализа существующих разрешений в Tessa:
Дата и время Сотрудники Всего дублей Максимум одинаковых разрешений
0 2026-05-29 14:28:54 Алексеев Л.Р. 5 5
1 2026-05-29 14:28:55 Андреев Л.К. 1 1
2 2026-05-29 14:28:57 Виноградов Т.Г. 1 2
3 2026-05-29 14:28:57 Волков А.В. 1 4
4 2026-05-29 14:28:57 Герасимов С.А. 1 2
5 2026-05-29 14:28:58 Григорьева Т.Д. 2 7
6 2026-05-29 14:28:58 Зайцев Р.С. 1 4
7 2026-05-29 14:29:00 Козлова К.Р. 1 1
8 2026-05-29 14:29:00 Кудрявцева С.М. 1 6
9 2026-05-29 14:29:01 Куликов Р.А. 1 5
10 2026-05-29 14:29:03 Новиков В.М. 2 5
11 2026-05-29 14:29:03 Новиков Г.Л. 1 4
12 2026-05-29 14:29:04 Семёнов Г.Т. 1 6
13 2026-05-29 14:29:05 Соловьёв А.Е. 4 3
14 2026-05-29 14:29:07 Фёдорова А.Е. 2 5
In [23]:
# Статистические данные результатов анализа разрешений
print('Статистические данные результатов:')
for col in total.columns:
    print()
    display(pd.DataFrame(total[col].describe()))
Статистические данные результатов:

Дата и время
count 15
mean 2026-05-29 14:28:59.933333248
min 2026-05-29 14:28:54
25% 2026-05-29 14:28:57
50% 2026-05-29 14:29:00
75% 2026-05-29 14:29:03
max 2026-05-29 14:29:07

Сотрудники
count 15
unique 15
top Алексеев Л.Р.
freq 1

Всего дублей
count 15
unique 4
top 1
freq 10

Максимум одинаковых разрешений
count 15
unique 7
top 5
freq 4
In [24]:
# Данные о количестве разрешений у сотрудника с максимальным количеством дублей
total_max = total[total['Всего дублей'] == total['Всего дублей'].max()]
display(total_max)
print(f"У сотрудников, перечисленных выше, максимальное количество правил доступа, \
дублирующих разрешения в других правилах доступа. Максимальное количество дублей \
увеличивает вероятность их пересечения с дублями разрешений у других сотрудников, \
поэтому оптимизацию существующих разрешений в Tessa предлагается начать c этого сотрудника.")
Дата и время Сотрудники Всего дублей Максимум одинаковых разрешений
0 2026-05-29 14:28:54 Алексеев Л.Р. 5 5
У сотрудников, перечисленных выше, максимальное количество правил доступа, дублирующих разрешения в других правилах доступа. Максимальное количество дублей увеличивает вероятность их пересечения с дублями разрешений у других сотрудников, поэтому оптимизацию существующих разрешений в Tessa предлагается начать c этого сотрудника.

Выводы¶

В результате анализа разрешений из имеющихся файлов, выгруженных из базы данных Tessa (в данном случае, сгенерированных с помощью генератора датафрейма тестовых данных Tessa), с разделением данных по чанкам по сотрудникам выявлено 10 сотрудников, с наиболее распространенным количеством объектов равным 2 и количеством одинаковых разрешений равным 5. У сотрудника Алексеева Л.Р. наибольшее количество дублей разрешений. Это означает:

  1. 10 сотрудникам были предоставлены дублями разрешения в разных правилах доступа.
  2. Большинству сотрудников предоставлено по 2 дубля разрешений.
  3. В большинстве дублей по 5 разрешений.
  4. Оптимизацию существующих разрешений в Tessa предлагается начать с Алексеева Л.Р., т.к. у него максимальное количество правил доступа, дублирующих разрешения, что увеличивает их пересечение с аналогичными дублями у других сотрудников.

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

Предыдущая статьяУдаленная диагностика сетиСледующая статья Кто управляет информацией, тот управляет миром

Рубрики

Метки

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

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

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




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


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