1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.provisioning.java;
20
21 import java.time.OffsetDateTime;
22 import java.util.Arrays;
23 import java.util.Optional;
24 import java.util.stream.Collectors;
25 import org.apache.commons.lang3.SerializationUtils;
26 import org.apache.syncope.common.lib.audit.AuditEntry;
27 import org.apache.syncope.common.lib.request.UserCR;
28 import org.apache.syncope.common.lib.request.UserUR;
29 import org.apache.syncope.common.lib.to.UserTO;
30 import org.apache.syncope.common.lib.types.AuditElements;
31 import org.apache.syncope.common.lib.types.AuditElements.Result;
32 import org.apache.syncope.common.lib.types.AuditLoggerName;
33 import org.apache.syncope.core.persistence.api.dao.AuditConfDAO;
34 import org.apache.syncope.core.persistence.api.entity.AuditConf;
35 import org.apache.syncope.core.provisioning.api.AuditManager;
36 import org.apache.syncope.core.provisioning.api.event.AfterHandlingEvent;
37 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
38 import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
39 import org.apache.syncope.core.spring.security.AuthContextUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.springframework.transaction.annotation.Propagation;
43 import org.springframework.transaction.annotation.Transactional;
44
45 @Transactional(readOnly = true)
46 public class DefaultAuditManager implements AuditManager {
47
48 protected static final String MASKED_VALUE = "<MASKED>";
49
50 protected static Object maskSensitive(final Object object) {
51 Object masked;
52
53 if (object instanceof UserTO) {
54 masked = SerializationUtils.clone((UserTO) object);
55 if (((UserTO) masked).getPassword() != null) {
56 ((UserTO) masked).setPassword(MASKED_VALUE);
57 }
58 if (((UserTO) masked).getSecurityAnswer() != null) {
59 ((UserTO) masked).setSecurityAnswer(MASKED_VALUE);
60 }
61 } else if (object instanceof UserCR) {
62 masked = SerializationUtils.clone((UserCR) object);
63 if (((UserCR) masked).getPassword() != null) {
64 ((UserCR) masked).setPassword(MASKED_VALUE);
65 }
66 if (((UserCR) masked).getSecurityAnswer() != null) {
67 ((UserCR) masked).setSecurityAnswer(MASKED_VALUE);
68 }
69 } else if (object instanceof UserUR && ((UserUR) object).getPassword() != null) {
70 masked = SerializationUtils.clone((UserUR) object);
71 ((UserUR) masked).getPassword().setValue(MASKED_VALUE);
72 } else {
73 masked = object;
74 }
75
76 return masked;
77 }
78
79 protected final AuditConfDAO auditConfDAO;
80
81 public DefaultAuditManager(final AuditConfDAO auditConfDAO) {
82 this.auditConfDAO = auditConfDAO;
83 }
84
85 @Override
86 public boolean auditRequested(
87 final String who,
88 final AuditElements.EventCategoryType type,
89 final String category,
90 final String subcategory,
91 final String event) {
92
93 AuditEntry auditEntry = new AuditEntry();
94 auditEntry.setWho(who);
95 auditEntry.setLogger(new AuditLoggerName(type, category, subcategory, event, Result.SUCCESS));
96 auditEntry.setDate(OffsetDateTime.now());
97
98 AuditConf auditConf = auditConfDAO.find(auditEntry.getLogger().toAuditKey());
99 boolean auditRequested = auditConf != null && auditConf.isActive();
100
101 if (auditRequested) {
102 return true;
103 }
104
105 auditEntry.setLogger(new AuditLoggerName(type, category, subcategory, event, Result.FAILURE));
106
107 auditConf = auditConfDAO.find(auditEntry.getLogger().toAuditKey());
108 auditRequested = auditConf != null && auditConf.isActive();
109
110 return auditRequested;
111 }
112
113 @Transactional(propagation = Propagation.NOT_SUPPORTED)
114 @Override
115 public void audit(final AfterHandlingEvent event) {
116 audit(
117 event.getWho(),
118 event.getType(),
119 event.getCategory(),
120 event.getSubcategory(),
121 event.getEvent(),
122 event.getCondition(),
123 event.getBefore(),
124 event.getOutput(),
125 event.getInput());
126 }
127
128 @Transactional(propagation = Propagation.NOT_SUPPORTED)
129 @Override
130 public void audit(
131 final String who,
132 final AuditElements.EventCategoryType type,
133 final String category,
134 final String subcategory,
135 final String event,
136 final Result condition,
137 final Object before,
138 final Object output,
139 final Object... input) {
140
141 AuditLoggerName auditLoggerName = new AuditLoggerName(type, category, subcategory, event, condition);
142
143 Optional.ofNullable(auditConfDAO.find(auditLoggerName.toAuditKey())).
144 filter(AuditConf::isActive).ifPresent(audit -> {
145
146 Throwable throwable = output instanceof Throwable
147 ? (Throwable) output
148 : null;
149
150 AuditEntry auditEntry = new AuditEntry();
151 auditEntry.setWho(who);
152 auditEntry.setLogger(auditLoggerName);
153 auditEntry.setDate(OffsetDateTime.now());
154 auditEntry.setBefore(POJOHelper.serialize((maskSensitive(before))));
155 if (throwable == null) {
156 auditEntry.setOutput(POJOHelper.serialize((maskSensitive(output))));
157 } else {
158 auditEntry.setOutput(throwable.getMessage());
159 auditEntry.setThrowable(ExceptionUtils2.getFullStackTrace(throwable));
160 }
161 if (input != null) {
162 auditEntry.getInputs().addAll(Arrays.stream(input).
163 map(DefaultAuditManager::maskSensitive).map(POJOHelper::serialize).
164 collect(Collectors.toList()));
165 }
166
167 Logger logger = LoggerFactory.getLogger(
168 AuditLoggerName.getAuditLoggerName(AuthContextUtils.getDomain()));
169 Logger eventLogger = LoggerFactory.getLogger(
170 AuditLoggerName.getAuditEventLoggerName(AuthContextUtils.getDomain(), audit.getKey()));
171 String serializedAuditEntry = POJOHelper.serialize(auditEntry);
172
173 if (throwable == null) {
174 logger.debug(serializedAuditEntry);
175 eventLogger.debug(serializedAuditEntry);
176 } else {
177 logger.debug(serializedAuditEntry, throwable);
178 eventLogger.debug(serializedAuditEntry, throwable);
179 }
180 });
181 }
182 }