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 платформа Data Lakehouse ELT excel ms sql pandas PostgreSQL PowerShell Python sql tessa VBA xyz анализ виртуальный помощник гибридное хранилище данных данные знания информационная система информация кластерный анализ комбинаторика компетенции корпоративная информационная система маркетинг математика медальон-архитектура модель предоставления прав мудрость о проекте оптимизация ошибка практика программное обеспечение пэст ролевая модель сеть; теория теория вероятностей тесса тест юмор языки программирования

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

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




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


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