Skip to content

Commit

Permalink
Add role mining data export using Ninja.
Browse files Browse the repository at this point in the history
  • Loading branch information
tchrapovic committed May 26, 2023
1 parent c5b651f commit b416169
Show file tree
Hide file tree
Showing 9 changed files with 946 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* 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.common;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang3.RandomStringUtils;
import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;

import org.jetbrains.annotations.Nullable;

public class RoleMiningExportUtils implements Serializable {

public static final String APPLICATION_ROLE_IDENTIFIER = "Application role";
public static final String BUSINESS_ROLE_IDENTIFIER = "Business role";
private static final String EXPORT_SUFFIX = "_AE";

public enum NameMode {
ENCRYPTED("ENCRYPTED"),
SEQUENTIAL("SEQUENTIAL"),
ORIGINAL("ORIGINAL");

private final String displayString;

NameMode(String displayString) {
this.displayString = displayString;
}

public String getDisplayString() {
return displayString;
}
}

public enum SecurityMode {
STANDARD("STANDARD"),
ADVANCED("ADVANCED");
private final String displayString;

SecurityMode(String displayString) {
this.displayString = displayString;
}

public String getDisplayString() {
return displayString;
}
}

private static PolyStringType encryptName(String name, int iterator, String prefix, @NotNull NameMode nameMode, String key) {
if (nameMode.equals(NameMode.ENCRYPTED)) {
return PolyStringType.fromOrig(encrypt(name, key) + EXPORT_SUFFIX);
} else if (nameMode.equals(NameMode.SEQUENTIAL)) {
return PolyStringType.fromOrig(prefix + iterator + EXPORT_SUFFIX);
} else if (nameMode.equals(NameMode.ORIGINAL)) {
return PolyStringType.fromOrig(name + EXPORT_SUFFIX);
}
return PolyStringType.fromOrig(prefix + iterator + EXPORT_SUFFIX);
}

public static PolyStringType encryptUserName(String name, int iterator, NameMode nameMode, String key) {
return encryptName(name, iterator, "User", nameMode, key);
}

public static PolyStringType encryptOrgName(String name, int iterator, NameMode nameMode, String key) {
return encryptName(name, iterator, "Organization", nameMode, key);
}

public static PolyStringType encryptRoleName(String name, int iterator, NameMode nameMode, String key) {
return encryptName(name, iterator, "Role", nameMode, key);
}

public static AssignmentType encryptObjectReference(@NotNull AssignmentType assignmentObject,
SecurityMode securityMode, String key) {
ObjectReferenceType encryptedTargetRef = assignmentObject.getTargetRef();
encryptedTargetRef.setOid(encryptedUUID(encryptedTargetRef.getOid(), securityMode, key));
return new AssignmentType().targetRef(encryptedTargetRef);
}

public static String encryptedUUID(String oid, SecurityMode securityMode, String key) {
UUID uuid = UUID.fromString(oid);
byte[] bytes = uuidToBytes(uuid, securityMode);
return UUID.nameUUIDFromBytes(encryptOid(bytes, key).getBytes()).toString();
}

private static byte @NotNull [] uuidToBytes(UUID uuid, @NotNull SecurityMode securityMode) {
ByteBuffer buffer = ByteBuffer.allocate(32);
if (securityMode.equals(SecurityMode.STANDARD)) {
buffer = ByteBuffer.allocate(16);
}
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
return buffer.array();
}

private static String encryptOid(byte[] value, String key) {

if (value == null) {
return null;
}
else if (key == null) {
return new String(value, StandardCharsets.UTF_8);
}

Cipher cipher;
byte[] ciphertext;
try {
byte[] keyBytes = key.getBytes();
cipher = Cipher.getInstance("AES");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
ciphertext = cipher.doFinal(value);
return Base64.getEncoder().encodeToString(ciphertext);
} catch (Exception e) {
throw new UnsupportedOperationException(getErrorEncryptMessage(e));
}
}

private static String encrypt(String value, String key) {

if (value == null) {
return null;
} else if (key == null) {
return value;
}

Cipher cipher;
byte[] ciphertext;
try {
byte[] keyBytes = key.getBytes();
cipher = Cipher.getInstance("AES");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
ciphertext = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(ciphertext);
} catch (Exception e) {
throw new UnsupportedOperationException(getErrorEncryptMessage(e));
}
}

public static @NotNull String updateEncryptKey(@NotNull SecurityMode securityMode) {
int keyLength = 32;
if (securityMode.equals(SecurityMode.STANDARD)) {
keyLength = 16;
}

return RandomStringUtils.random(keyLength, 0, 0, true, true, null,
new SecureRandom());
}

public static @Nullable String determineRoleCategory(String name, List<String> applicationRolePrefix,
List<String> businessRolePrefix, List<String> applicationRoleSuffix, List<String> businessRoleSuffix) {

if (applicationRolePrefix != null && !applicationRolePrefix.isEmpty()) {
if (applicationRolePrefix.stream().anyMatch(rolePrefix -> name.toLowerCase().startsWith(rolePrefix.toLowerCase()))) {
return APPLICATION_ROLE_IDENTIFIER;
}
}

if (applicationRoleSuffix != null && !applicationRoleSuffix.isEmpty()) {
if (applicationRoleSuffix.stream().anyMatch(roleSuffix -> name.toLowerCase().endsWith(roleSuffix.toLowerCase()))) {
return APPLICATION_ROLE_IDENTIFIER;
}
}

if (businessRolePrefix != null && !businessRolePrefix.isEmpty()) {
if (businessRolePrefix.stream().anyMatch(rolePrefix -> name.toLowerCase().startsWith(rolePrefix.toLowerCase()))) {
return BUSINESS_ROLE_IDENTIFIER;
}
}

if (businessRoleSuffix != null && !businessRoleSuffix.isEmpty()) {
if (businessRoleSuffix.stream().anyMatch(roleSuffix -> name.toLowerCase().endsWith(roleSuffix.toLowerCase()))) {
return BUSINESS_ROLE_IDENTIFIER;
}
}
return null;
}

private static @NotNull String getErrorEncryptMessage(@NotNull Exception e) {
return "Error: Invalid key - Possible causes:\n"
+ "- The key is not the right size or format for this operation.\n"
+ "- The key is not appropriate for the selected algorithm or mode of operation.\n"
+ "- The key has been damaged or corrupted.\n"
+ "Error message: " + e.getMessage();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.ninja.action.mining;

import com.beust.jcommander.Parameter;

import com.evolveum.midpoint.ninja.util.FileReference;
import com.evolveum.midpoint.ninja.util.FileReferenceConverter;

public class BaseMiningOptions {

public static final String P_FILTER_ROLE = "-fr";
public static final String P_FILTER_ROLE_LONG = "--filterRole";
public static final String P_FILTER_USER = "-fu";
public static final String P_FILTER_USER_LONG = "--filterUser";
public static final String P_FILTER_ORG = "-fo";
public static final String P_FILTER_ORG_LONG = "--filterOrg";
public static final String P_ZIP = "-z";
public static final String P_ZIP_LONG = "--zip";
public static final String P_MULTI_THREAD = "-l";
public static final String P_MULTI_THREAD_LONG = "--multi-thread";

@Parameter(names = { P_FILTER_ROLE, P_FILTER_ROLE_LONG }, descriptionKey = "base.filterRole",
converter = FileReferenceConverter.class, validateWith = FileReferenceConverter.class)
private FileReference roleFilter;

@Parameter(names = { P_FILTER_USER, P_FILTER_USER_LONG }, descriptionKey = "base.filterUser",
converter = FileReferenceConverter.class, validateWith = FileReferenceConverter.class)
private FileReference userFilter;

@Parameter(names = { P_FILTER_ORG, P_FILTER_ORG_LONG }, descriptionKey = "base.filterOrg",
converter = FileReferenceConverter.class, validateWith = FileReferenceConverter.class)
private FileReference orgFilter;

@Parameter(names = { P_ZIP, P_ZIP_LONG }, descriptionKey = "baseImportExport.zip")
private boolean zip;

@Parameter(names = { P_MULTI_THREAD, P_MULTI_THREAD_LONG }, descriptionKey = "baseImportExport.multiThread")
private int multiThread = 1;

public FileReference getRoleFilter() {
return roleFilter;
}

public FileReference getUserFilter() {
return userFilter;
}

public FileReference getOrgFilter() {
return orgFilter;
}

public boolean isZip() {
return zip;
}

public int getMultiThread() {
return multiThread;
}
}

0 comments on commit b416169

Please sign in to comment.