Skip to content

Commit

Permalink
Update role mining feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
tchrapovic committed Jun 13, 2023
1 parent e0a72f4 commit d61b9f4
Show file tree
Hide file tree
Showing 53 changed files with 4,348 additions and 98 deletions.
1 change: 1 addition & 0 deletions config/sql/native-new/postgres-new-audit.sql
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ DO $$ BEGIN
'REPORT_DATA',
'RESOURCE',
'ROLE',
'MINING',
'SECURITY_POLICY',
'SEQUENCE',
'SERVICE',
Expand Down
35 changes: 35 additions & 0 deletions config/sql/native-new/postgres-new.sql
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ CREATE TYPE ContainerType AS ENUM (
'SIMULATION_RESULT_PROCESSED_OBJECT',
'TRIGGER');

ALTER TYPE ObjectType ADD VALUE 'MINING';
-- NOTE: Keep in sync with the same enum in postgres-new-audit.sql!
CREATE TYPE ObjectType AS ENUM (
'ABSTRACT_ROLE',
Expand Down Expand Up @@ -75,6 +76,7 @@ CREATE TYPE ObjectType AS ENUM (
'REPORT_DATA',
'RESOURCE',
'ROLE',
'MINING',
'SECURITY_POLICY',
'SEQUENCE',
'SERVICE',
Expand Down Expand Up @@ -1153,6 +1155,39 @@ CREATE INDEX m_report_data_policySituation_idx
CREATE INDEX m_report_data_createTimestamp_idx ON m_report_data (createTimestamp);
CREATE INDEX m_report_data_modifyTimestamp_idx ON m_report_data (modifyTimestamp);


CREATE TABLE m_mining_table (
oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid),
objectType ObjectType GENERATED ALWAYS AS ('MINING') STORED
CHECK (objectType = 'MINING'),
identifier TEXT,
riskLevel TEXT,
roles TEXT[],
rolesCount INTEGER,
members TEXT[],
membersCount INTEGER,
similarGroups TEXT[],
similarGroupsCount INTEGER
)
INHERITS (m_assignment_holder);

CREATE TRIGGER m_mining_table_oid_insert_tr BEFORE INSERT ON m_mining_table
FOR EACH ROW EXECUTE FUNCTION insert_object_oid();
CREATE TRIGGER m_mining_table_update_tr BEFORE UPDATE ON m_mining_table
FOR EACH ROW EXECUTE FUNCTION before_update_object();
CREATE TRIGGER m_mining_table_oid_delete_tr AFTER DELETE ON m_mining_table
FOR EACH ROW EXECUTE FUNCTION delete_object_oid();

CREATE INDEX m_mining_table_identifier_idx ON m_mining_table (identifier);
CREATE INDEX m_mining_table_riskLevel_idx ON m_mining_table (riskLevel);
CREATE INDEX m_mining_table_roles_idx ON m_mining_table (roles);
CREATE INDEX m_mining_table_rolesCount_idx ON m_mining_table (rolesCount);
CREATE INDEX m_mining_table_membersCount_idx ON m_mining_table (membersCount);
CREATE INDEX m_mining_table_similarGroupsCount_idx ON m_mining_table (similarGroupsCount);




-- Represents LookupTableType, see https://docs.evolveum.com/midpoint/reference/misc/lookup-tables/
CREATE TABLE m_lookup_table (
oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid),
Expand Down
2 changes: 1 addition & 1 deletion gui/admin-gui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@
<include>**/org.identityconnectors.common.logging</include>
</includes>
</resource>

<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2010-2023 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.gui.api.component.mining.analyse.tools.grouper;

import com.evolveum.midpoint.gui.api.component.mining.analyse.tools.jaccard.UniqueRoleSet;
import com.evolveum.midpoint.gui.api.component.mining.analyse.tools.utils.RoleUtils;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.util.OidUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static com.evolveum.midpoint.gui.api.component.mining.analyse.tools.utils.RoleUtils.getRolesId;
import static com.evolveum.midpoint.gui.api.component.mining.analyse.tools.utils.RoleUtils.intersectionCount;

public class Grouper {
private static List<PrismObject<UserType>> extractUsersWithMinimumIntersection(List<PrismObject<UserType>> users,
int minIntersection) {
List<PrismObject<UserType>> result = new ArrayList<>();

for (int i = 0; i < users.size(); i++) {
PrismObject<UserType> currentUser = users.get(i);
int intersectionCount = 0;

for (int j = 0; j < users.size(); j++) {
if (i != j) {
PrismObject<UserType> otherUser = users.get(j);

List<String> currentUserValues = getRolesId(currentUser.asObjectable());
List<String> otherUserValues = getRolesId(otherUser.asObjectable());

int matchingValues = intersectionCount(currentUserValues, otherUserValues);

if (matchingValues >= minIntersection) {
intersectionCount++;
}
}
}

if (intersectionCount >= minIntersection) {
result.add(currentUser);
}
}

return result;
}

public static List<UniqueRoleSet> generateIntersectionGroups(List<PrismObject<UserType>> users, int minIntersection) {

List<UniqueRoleSet> usersGroupedByRoles = new ArrayList<>();

List<PrismObject<UserType>> userTypeList;
List<String> roleTypeList;
for (int i = 1; i < users.size(); i++) {
PrismObject<UserType> userA = users.get(i);
roleTypeList = new ArrayList<>(getRolesId(userA.asObjectable()));
userTypeList = new ArrayList<>();
userTypeList.add(userA);

for (PrismObject<UserType> userB : users) {
int similarity = intersectionCount(getRolesId(userA.asObjectable()), getRolesId(userB.asObjectable()));
if (similarity >= minIntersection) {
userTypeList.add(userB);
}
}

List<PrismObject<UserType>> prismObjects = extractUsersWithMinimumIntersection(userTypeList, minIntersection);
usersGroupedByRoles.add(new UniqueRoleSet(userA.getName().toString(), roleTypeList, prismObjects));
}

return usersGroupedByRoles;
}

public static List<UniqueRoleSet> generateUniqueSetsGroup(List<PrismObject<UserType>> users) {

Map<String, List<PrismObject<UserType>>> roleUserMap = new TreeMap<>();
for (PrismObject<UserType> user : users) {
List<String> roles = new ArrayList<>(getRolesId(user.asObjectable()));
if (roles.isEmpty()) {
continue;
}

String roleKey = roles.toString();

if (roleUserMap.containsKey(roleKey)) {
roleUserMap.get(roleKey).add(user);
} else {
List<PrismObject<UserType>> userList = new ArrayList<>();
userList.add(user);
roleUserMap.put(roleKey, userList);
}
}

List<UniqueRoleSet> usersGroupedByRoles = new ArrayList<>();

for (List<PrismObject<UserType>> usersList : roleUserMap.values()) {
usersGroupedByRoles.add(new UniqueRoleSet(OidUtil.generateOid(),
getRolesId(usersList.get(0).asObjectable()), usersList));
}

return usersGroupedByRoles;
}


public static List<UniqueRoleSet> getRoleGroupByJc(List<PrismObject<UserType>> users, double threshold) {

List<UniqueRoleSet> usersGroupedByRoles = new ArrayList<>();

List<PrismObject<UserType>> userTypeList;
List<String> roleTypeList;
for (int i = 1; i < users.size(); i++) {
PrismObject<UserType> userA = users.get(i);
roleTypeList = new ArrayList<>(getRolesId(userA.asObjectable()));
userTypeList = new ArrayList<>();
userTypeList.add(userA);

for (int j = i + 1; j < users.size(); j++) {
PrismObject<UserType> userB = users.get(j);
double similarity = RoleUtils.jacquardSimilarity(
getRolesId(userA.asObjectable()), getRolesId(userB.asObjectable()));
if (similarity >= threshold) {
userTypeList.add(userB);
}
}
usersGroupedByRoles.add(new UniqueRoleSet(OidUtil.generateOid(), roleTypeList, userTypeList));

}

return usersGroupedByRoles;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010-2023 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.gui.api.component.mining.analyse.tools.grouper;

import java.io.Serializable;
import java.util.List;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.web.component.util.SelectableBeanImpl;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

public class MiningSet extends SelectableBeanImpl<MiningSet> implements Serializable {
public static final String F_RATION = "groupOverlapRation";
public static final String F_GROUP = "groupIdentifier";
public static final String F_USER_SIZE = "users";
public static final String F_ID = "id";
public static final String F_ROLES_BY_TRESHOLD = "rolesByThresholdId";

int groupIdentifier;
double groupOverlapRation;
List<String> roles;
List<PrismObject<UserType>> users;
List<Integer> rolesByThresholdId;
private boolean selected;

public String getId() {
return id;
}

String id;

public MiningSet(String id, int groupIdentifier, double groupOverlapRation, List<String> roles,
List<Integer> rolesByThresholdId, List<PrismObject<UserType>> users) {
this.groupIdentifier = groupIdentifier;
this.groupOverlapRation = groupOverlapRation;
this.roles = roles;
this.rolesByThresholdId = rolesByThresholdId;
this.users = users;
this.id = id;

}

public void setSelected(boolean selected) {
this.selected = selected;
}

public int getGroupIdentifier() {
return groupIdentifier;
}

public double getGroupOverlapRation() {
return groupOverlapRation;
}

public List<String> getRoles() {
return roles;
}

public List<PrismObject<UserType>> getUsers() {
return users;
}

public List<Integer> getRolesByThresholdId() {
return rolesByThresholdId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2010-2023 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.gui.api.component.mining.analyse.tools.grouper;

import static com.evolveum.midpoint.gui.api.component.mining.analyse.tools.jaccard.JacquardSorter.jaccSortUn;
import static com.evolveum.midpoint.gui.api.component.mining.analyse.tools.grouper.Grouper.generateIntersectionGroups;
import static com.evolveum.midpoint.gui.api.component.mining.analyse.tools.grouper.Grouper.generateUniqueSetsGroup;

import java.util.ArrayList;
import java.util.List;

import com.evolveum.midpoint.gui.api.component.mining.analyse.tools.utils.RoleUtils;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.gui.api.component.mining.analyse.tools.jaccard.UniqueRoleSet;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

public class Preparer {

public @NotNull
static List<MiningSet> prepareMiningSet(List<PrismObject<UserType>> users, double threshold) {
List<MiningSet> miningSets = new ArrayList<>();
List<UniqueRoleSet> uniqueRoleSet = jaccSortUn(generateUniqueSetsGroup(users));
int size = uniqueRoleSet.size();

for (int i = 0; i < size; i++) {
List<Integer> rolesByThreshold = new ArrayList<>();
double ration = 0;
for (int j = 0; j < size; j++) {
if (j != i) {

double similarity = RoleUtils.jacquardSimilarity(uniqueRoleSet.get(i).getRoles(),
uniqueRoleSet.get(j).getRoles());
ration += similarity;

if (similarity >= threshold) {
rolesByThreshold.add(j);
}

}
}
ration /= size;
UniqueRoleSet roleSet = uniqueRoleSet.get(i);
miningSets.add(new MiningSet(uniqueRoleSet.get(i).getoId(),
i, ration, roleSet.getRoles(), rolesByThreshold, roleSet.getUsers()));
}
return miningSets;
}

public @NotNull
static List<MiningSet> prepareMiningSetIntersected(List<PrismObject<UserType>> users, int minIntersection, double threshold) {
List<MiningSet> miningSets = new ArrayList<>();
List<UniqueRoleSet> uniqueRoleSet = jaccSortUn(generateIntersectionGroups(users, minIntersection));
int size = uniqueRoleSet.size();

for (int i = 0; i < size; i++) {
List<Integer> rolesByThreshold = new ArrayList<>();
double ration = 0;
for (int j = 0; j < size; j++) {
if (j != i) {

double similarity = RoleUtils.jacquardSimilarity(uniqueRoleSet.get(i).getRoles(),
uniqueRoleSet.get(j).getRoles());
ration += similarity;

if (similarity >= threshold) {
rolesByThreshold.add(j);
}

}
}
ration /= size;
UniqueRoleSet roleSet = uniqueRoleSet.get(i);
miningSets.add(new MiningSet(uniqueRoleSet.get(i).getoId(), i, ration, roleSet.getRoles(),
rolesByThreshold, roleSet.getUsers()));
}
return miningSets;
}

}

0 comments on commit d61b9f4

Please sign in to comment.