Skip to content

Commit

Permalink
Merge branch 'support-4.7' of https://github.com/Evolveum/midpoint in…
Browse files Browse the repository at this point in the history
…to support-4.7
  • Loading branch information
Kateryna Honchar committed May 29, 2023
2 parents 407b890 + 221c444 commit 360209c
Show file tree
Hide file tree
Showing 19 changed files with 1,159 additions and 33 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
Expand Up @@ -67,7 +67,12 @@ FocusType checkCredentials(ConnectionEnvironment connEnv, T authnCtx)
* @param connEnv
* @param authnCtx
* @return token with {@link com.evolveum.midpoint.security.api.MidPointPrincipal}
* @throws DisabledException when object found by authentication identifier is disabled
* @throws AuthenticationServiceException when occur some internal server error during authentication
* @throws UsernameNotFoundException when object not found by authentication identifier
*/
<AC extends AbstractAuthenticationContext> PreAuthenticatedAuthenticationToken authenticateUserPreAuthenticated(ConnectionEnvironment connEnv, AC authnCtx);
<AC extends AbstractAuthenticationContext> PreAuthenticatedAuthenticationToken authenticateUserPreAuthenticated(
ConnectionEnvironment connEnv, AC authnCtx)
throws DisabledException, AuthenticationServiceException, UsernameNotFoundException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ public String getAndCheckUserPassword(ConnectionEnvironment connEnv, String user
}

@Override
public <AC extends AbstractAuthenticationContext> PreAuthenticatedAuthenticationToken authenticateUserPreAuthenticated(ConnectionEnvironment connEnv, AC authnCtx) {
public <AC extends AbstractAuthenticationContext> PreAuthenticatedAuthenticationToken authenticateUserPreAuthenticated(
ConnectionEnvironment connEnv, AC authnCtx)
throws DisabledException, AuthenticationServiceException, UsernameNotFoundException {

MidPointPrincipal principal = getAndCheckPrincipal(connEnv, authnCtx, authnCtx.isSupportActivationByChannel());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import com.evolveum.midpoint.authentication.api.AuthenticationChannel;

import com.evolveum.midpoint.authentication.impl.filter.RefuseUnauthenticatedRequestFilter;
import com.evolveum.midpoint.authentication.impl.module.configurer.ModuleWebSecurityConfigurer;

import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
Expand All @@ -24,6 +25,8 @@

import com.evolveum.midpoint.schema.constants.SchemaConstants;

import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;

/**
* @author skublik
*/
Expand Down Expand Up @@ -76,9 +79,11 @@ protected void isSupportedChannel(AuthenticationChannel authenticationChannel) {
}
}

protected HttpSecurity getNewHttpSecurity(ModuleWebSecurityConfigurer module) throws Exception {
HttpSecurity getNewHttpSecurity(ModuleWebSecurityConfigurer module) throws Exception {
module.setObjectPostProcessor(getObjectObjectPostProcessor());
return module.getNewHttpSecurity();
HttpSecurity httpSecurity = module.getNewHttpSecurity();
httpSecurity.addFilterAfter(new RefuseUnauthenticatedRequestFilter(), SwitchUserFilter.class);
return httpSecurity;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ public class LdapModuleFactory extends AbstractModuleFactory {
@Autowired
private Protector protector;

@Autowired
private GuiProfiledPrincipalManager principalManager;

@Override
public boolean match(AbstractAuthenticationModuleType moduleType, AuthenticationChannel authenticationChannel) {
return moduleType instanceof LdapAuthenticationModuleType;
Expand Down Expand Up @@ -111,7 +108,7 @@ private AuthenticationProvider getProvider(LdapAuthenticationModuleType moduleTy
getObjectObjectPostProcessor().postProcess(auth);

MidPointLdapAuthenticationProvider provider = new MidPointLdapAuthenticationProvider(auth);
provider.setUserDetailsContextMapper(new MidpointPrincipalContextMapper(principalManager));
provider.setUserDetailsContextMapper(getObjectObjectPostProcessor().postProcess(new MidpointPrincipalContextMapper()));
getObjectObjectPostProcessor().postProcess(provider.getAuthenticatorProvider());
getObjectObjectPostProcessor().postProcess(provider);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.authentication.impl.filter;

import com.evolveum.midpoint.authentication.api.config.MidpointAuthentication;
import com.evolveum.midpoint.authentication.impl.util.AuthSequenceUtil;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RefuseUnauthenticatedRequestFilter extends OncePerRequestFilter {

private static final Trace LOGGER = TraceManager.getTrace(RefuseUnauthenticatedRequestFilter.class);

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Authentication mpAuthentication = SecurityContextHolder.getContext().getAuthentication();
if (AuthSequenceUtil.isPermitAll(request)
|| AuthSequenceUtil.isLoginPage(request)
|| (mpAuthentication instanceof MidpointAuthentication && mpAuthentication.isAuthenticated())) {
filterChain.doFilter(request, response);
return;
}

LOGGER.debug("Unauthenticated request");
throw new AuthenticationServiceException("Unauthenticated request");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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.authentication.impl.ldap;

import org.springframework.security.core.AuthenticationException;

public class AuditedAuthenticationException extends AuthenticationException {
public AuditedAuthenticationException(AuthenticationException cause) {
super(cause.getMessage(), cause);
}

@Override
public synchronized AuthenticationException getCause() {
return (AuthenticationException) super.getCause();
}
}

0 comments on commit 360209c

Please sign in to comment.