This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch 4_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/4_0_X by this push:
new 8b32a341ce Ensuring to mask all sensitive values in audit records
8b32a341ce is described below
commit 8b32a341ced8ead9ff59478afae1dd1770fa80f5
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Mon Aug 17 14:45:06 2026 +0200
Ensuring to mask all sensitive values in audit records
---
.../provisioning/java/DefaultAuditManager.java | 110 ++++++++++++++++-----
.../java/data/ResourceDataBinderImpl.java | 1 +
2 files changed, 87 insertions(+), 24 deletions(-)
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
index 5c3abfb116..89f2cd57d8 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAuditManager.java
@@ -21,11 +21,16 @@ package org.apache.syncope.core.provisioning.java;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.common.keymaster.client.api.model.Domain;
import org.apache.syncope.common.lib.request.UserCR;
import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.common.lib.types.OpEvent;
import org.apache.syncope.core.persistence.api.dao.AuditConfDAO;
import org.apache.syncope.core.persistence.api.dao.AuditEventDAO;
@@ -49,33 +54,88 @@ public class DefaultAuditManager implements AuditManager {
protected static final String MASKED_VALUE = "<MASKED>";
+ protected static void maskSensitive(final List<ConnConfProperty> conf) {
+ conf.stream().filter(property ->
property.getSchema().isConfidential()).forEach(property -> {
+ int size = property.getValues().size();
+ property.getValues().clear();
+ for (int i = 0; i < size; i++) {
+ property.getValues().add(MASKED_VALUE);
+ }
+ });
+ }
+
protected static Object maskSensitive(final Object object) {
- Object masked;
+ return switch (object) {
+ case UserTO userTO -> {
+ UserTO clone = SerializationUtils.clone(userTO);
+ if (clone.getPassword() != null) {
+ clone.setPassword(MASKED_VALUE);
+ }
+ clone.getLinkedAccounts().forEach(linkedAccount -> {
+ if (linkedAccount.getPassword() != null) {
+ linkedAccount.setPassword(MASKED_VALUE);
+ }
+ });
+ yield clone;
+ }
+
+ case UserCR userCR -> {
+ UserCR clone = SerializationUtils.clone(userCR);
+ if (clone.getPassword() != null) {
+ clone.setPassword(MASKED_VALUE);
+ }
+ if (clone.getSecurityAnswer() != null) {
+ clone.setSecurityAnswer(MASKED_VALUE);
+ }
+ clone.getLinkedAccounts().forEach(linkedAccount -> {
+ if (linkedAccount.getPassword() != null) {
+ linkedAccount.setPassword(MASKED_VALUE);
+ }
+ });
+ yield clone;
+ }
+
+ case UserUR userUR -> {
+ UserUR clone = SerializationUtils.clone(userUR);
+ if (clone.getPassword() != null) {
+ clone.getPassword().setValue(MASKED_VALUE);
+ }
+ if (clone.getSecurityAnswer() != null) {
+ clone.getSecurityAnswer().setValue(MASKED_VALUE);
+ }
+ clone.getLinkedAccounts().forEach(linkedAccountUR ->
Optional.ofNullable(
+
linkedAccountUR.getLinkedAccountTO()).ifPresent(linkedAccount -> {
- if (object instanceof UserTO userTO) {
- masked = SerializationUtils.clone(userTO);
- if (((UserTO) masked).getPassword() != null) {
- ((UserTO) masked).setPassword(MASKED_VALUE);
+ if (linkedAccount.getPassword() != null) {
+ linkedAccount.setPassword(MASKED_VALUE);
+ }
+ }));
+ yield clone;
}
- if (((UserTO) masked).getSecurityAnswer() != null) {
- ((UserTO) masked).setSecurityAnswer(MASKED_VALUE);
+
+ case ConnInstanceTO connInstanceTO -> {
+ ConnInstanceTO clone =
SerializationUtils.clone(connInstanceTO);
+ maskSensitive(connInstanceTO.getConf());
+ yield clone;
}
- } else if (object instanceof UserCR userCR) {
- masked = SerializationUtils.clone(userCR);
- if (((UserCR) masked).getPassword() != null) {
- ((UserCR) masked).setPassword(MASKED_VALUE);
+
+ case ResourceTO resourceTO -> {
+ ResourceTO clone = SerializationUtils.clone(resourceTO);
+
clone.getConfOverride().ifPresent(DefaultAuditManager::maskSensitive);
+ yield clone;
}
- if (((UserCR) masked).getSecurityAnswer() != null) {
- ((UserCR) masked).setSecurityAnswer(MASKED_VALUE);
+
+ case Domain domain -> {
+ Domain clone = SerializationUtils.clone(domain);
+ clone.setAdminPassword(MASKED_VALUE);
+ yield clone;
}
- } else if (object instanceof final UserUR userUR &&
userUR.getPassword() != null) {
- masked = SerializationUtils.clone(userUR);
- ((UserUR) masked).getPassword().setValue(MASKED_VALUE);
- } else {
- masked = object;
- }
-
- return masked;
+
+ case null ->
+ null;
+ default ->
+ object;
+ };
}
protected final AuditConfDAO auditConfDAO;
@@ -172,17 +232,19 @@ public class DefaultAuditManager implements AuditManager {
auditEvent.setOpEvent(opEvent.toString());
auditEvent.setWho(who);
auditEvent.setWhen(OffsetDateTime.now());
-
auditEvent.setBefore(POJOHelper.serialize((maskSensitive(before))));
+ Optional.ofNullable(before).
+ ifPresent(b ->
auditEvent.setBefore(POJOHelper.serialize((maskSensitive(b)))));
Optional.ofNullable(input).ifPresent(in ->
auditEvent.setInputs(Arrays.stream(in).
-
map(DefaultAuditManager::maskSensitive).map(POJOHelper::serialize).
+
filter(Objects::nonNull).map(DefaultAuditManager::maskSensitive).map(POJOHelper::serialize).
toList()));
if (output instanceof Throwable throwable) {
auditEvent.setOutput(throwable.getMessage());
auditEvent.setThrowable(ExceptionUtils2.getFullStackTrace(throwable));
} else {
-
auditEvent.setOutput(POJOHelper.serialize((maskSensitive(output))));
+ Optional.ofNullable(output).
+ ifPresent(out ->
auditEvent.setOutput(POJOHelper.serialize((maskSensitive(out)))));
}
auditEventDAO.save(auditEvent);
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 9b3e9c62a0..eb750a3d96 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -594,6 +594,7 @@ public class ResourceDataBinderImpl implements
ResourceDataBinder {
? null : resource.getProvisionSorter().getKey());
// do not export confidential property values
+ resourceTO.setConfOverride(resource.getConfOverride());
resourceTO.getConfOverride().ifPresent(conf -> conf.stream().
filter(property -> property.getSchema().isConfidential()
||
GuardedString.class.getName().equals(property.getSchema().getType())).