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.utils;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Base64;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.syncope.common.lib.AnyOperations;
31 import org.apache.syncope.common.lib.Attr;
32 import org.apache.syncope.common.lib.EntityTOUtils;
33 import org.apache.syncope.common.lib.request.AnyCR;
34 import org.apache.syncope.common.lib.request.AnyUR;
35 import org.apache.syncope.common.lib.request.UserCR;
36 import org.apache.syncope.common.lib.to.AnyObjectTO;
37 import org.apache.syncope.common.lib.to.AnyTO;
38 import org.apache.syncope.common.lib.to.ConnObject;
39 import org.apache.syncope.common.lib.to.GroupTO;
40 import org.apache.syncope.common.lib.to.OrgUnit;
41 import org.apache.syncope.common.lib.to.Provision;
42 import org.apache.syncope.common.lib.to.RealmTO;
43 import org.apache.syncope.common.lib.to.UserTO;
44 import org.apache.syncope.common.lib.types.AnyTypeKind;
45 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
46 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
47 import org.apache.syncope.core.persistence.api.dao.UserDAO;
48 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
49 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
50 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
51 import org.apache.syncope.core.persistence.api.entity.user.User;
52 import org.apache.syncope.core.provisioning.api.MappingManager;
53 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
54 import org.apache.syncope.core.spring.security.Encryptor;
55 import org.apache.syncope.core.spring.security.PasswordGenerator;
56 import org.identityconnectors.common.security.GuardedByteArray;
57 import org.identityconnectors.common.security.GuardedString;
58 import org.identityconnectors.common.security.SecurityUtil;
59 import org.identityconnectors.framework.common.objects.Attribute;
60 import org.identityconnectors.framework.common.objects.ConnectorObject;
61 import org.identityconnectors.framework.common.objects.SyncToken;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.springframework.transaction.annotation.Transactional;
65 import org.springframework.util.CollectionUtils;
66
67 public class ConnObjectUtils {
68
69 protected static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtils.class);
70
71 protected static final Encryptor ENCRYPTOR = Encryptor.getInstance();
72
73 public static SyncToken toSyncToken(final String syncToken) {
74 return Optional.ofNullable(syncToken).map(st -> POJOHelper.deserialize(st, SyncToken.class)).orElse(null);
75 }
76
77 public static String toString(final SyncToken syncToken) {
78 return Optional.ofNullable(syncToken).map(POJOHelper::serialize).orElse(null);
79 }
80
81
82
83
84
85
86
87 public static String getPassword(final Object pwd) {
88 StringBuilder result = new StringBuilder();
89
90 if (pwd instanceof GuardedString) {
91 result.append(SecurityUtil.decrypt((GuardedString) pwd));
92 } else if (pwd instanceof GuardedByteArray) {
93 result.append(Arrays.toString(SecurityUtil.decrypt((GuardedByteArray) pwd)));
94 } else if (pwd instanceof String) {
95 result.append((String) pwd);
96 } else {
97 result.append(pwd.toString());
98 }
99
100 return result.toString();
101 }
102
103
104
105
106
107
108
109
110 public static ConnObject getConnObjectTO(final String fiql, final Set<Attribute> attrs) {
111 ConnObject connObjectTO = new ConnObject();
112 connObjectTO.setFiql(fiql);
113
114 if (!CollectionUtils.isEmpty(attrs)) {
115 connObjectTO.getAttrs().addAll(attrs.stream().map(attr -> {
116 Attr attrTO = new Attr();
117 attrTO.setSchema(attr.getName());
118
119 if (!CollectionUtils.isEmpty(attr.getValue())) {
120 attr.getValue().stream().filter(Objects::nonNull).forEach(value -> {
121 if (value instanceof GuardedString || value instanceof GuardedByteArray) {
122 attrTO.getValues().add(getPassword(value));
123 } else if (value instanceof byte[]) {
124 attrTO.getValues().add(Base64.getEncoder().encodeToString((byte[]) value));
125 } else {
126 attrTO.getValues().add(value.toString());
127 }
128 });
129 }
130
131 return attrTO;
132 }).collect(Collectors.toList()));
133 }
134
135 return connObjectTO;
136 }
137
138 protected final TemplateUtils templateUtils;
139
140 protected final RealmDAO realmDAO;
141
142 protected final UserDAO userDAO;
143
144 protected final ExternalResourceDAO resourceDAO;
145
146 protected final PasswordGenerator passwordGenerator;
147
148 protected final MappingManager mappingManager;
149
150 protected final AnyUtilsFactory anyUtilsFactory;
151
152 public ConnObjectUtils(
153 final TemplateUtils templateUtils,
154 final RealmDAO realmDAO,
155 final UserDAO userDAO,
156 final ExternalResourceDAO resourceDAO,
157 final PasswordGenerator passwordGenerator,
158 final MappingManager mappingManager,
159 final AnyUtilsFactory anyUtilsFactory) {
160
161 this.templateUtils = templateUtils;
162 this.realmDAO = realmDAO;
163 this.userDAO = userDAO;
164 this.resourceDAO = resourceDAO;
165 this.passwordGenerator = passwordGenerator;
166 this.mappingManager = mappingManager;
167 this.anyUtilsFactory = anyUtilsFactory;
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181
182 @Transactional(readOnly = true)
183 public <C extends AnyCR> C getAnyCR(
184 final ConnectorObject obj,
185 final PullTask pullTask,
186 final AnyTypeKind anyTypeKind,
187 final Provision provision,
188 final boolean generatePassword) {
189
190 AnyTO anyTO = getAnyTOFromConnObject(obj, pullTask, anyTypeKind, provision);
191 C anyCR = anyUtilsFactory.getInstance(anyTypeKind).newAnyCR();
192 EntityTOUtils.toAnyCR(anyTO, anyCR);
193
194
195 if (anyCR instanceof UserCR
196 && StringUtils.isBlank(((UserCR) anyCR).getPassword())
197 && generatePassword) {
198
199 UserCR userCR = (UserCR) anyCR;
200 List<PasswordPolicy> passwordPolicies = new ArrayList<>();
201
202
203 userCR.getResources().stream().
204 map(resourceDAO::find).
205 filter(r -> r != null && r.getPasswordPolicy() != null).
206 forEach(r -> passwordPolicies.add(r.getPasswordPolicy()));
207
208
209 Optional.ofNullable(realmDAO.findByFullPath(userCR.getRealm())).
210 ifPresent(realm -> realmDAO.findAncestors(realm).stream().
211 filter(ancestor -> ancestor.getPasswordPolicy() != null
212 && !passwordPolicies.contains(ancestor.getPasswordPolicy())).
213 forEach(ancestor -> passwordPolicies.add(ancestor.getPasswordPolicy())));
214
215 userCR.setPassword(passwordGenerator.generate(passwordPolicies));
216 }
217
218 return anyCR;
219 }
220
221 public RealmTO getRealmTO(final ConnectorObject obj, final OrgUnit orgUnit) {
222 RealmTO realmTO = new RealmTO();
223
224 MappingUtils.getPullItems(orgUnit.getItems().stream()).
225 forEach(item -> mappingManager.setIntValues(
226 item, obj.getAttributeByName(item.getExtAttrName()), realmTO));
227
228 return realmTO;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243 @SuppressWarnings("unchecked")
244 @Transactional(readOnly = true)
245 public <U extends AnyUR> U getAnyUR(
246 final String key,
247 final ConnectorObject obj,
248 final AnyTO original,
249 final PullTask pullTask,
250 final AnyTypeKind anyTypeKind,
251 final Provision provision) {
252
253 AnyTO updated = getAnyTOFromConnObject(obj, pullTask, anyTypeKind, provision);
254 updated.setKey(key);
255
256 U anyUR;
257 switch (provision.getAnyType()) {
258 case "USER":
259 UserTO originalUser = (UserTO) original;
260 UserTO updatedUser = (UserTO) updated;
261
262 if (StringUtils.isBlank(updatedUser.getUsername())) {
263 updatedUser.setUsername(originalUser.getUsername());
264 }
265
266
267 User user = userDAO.authFind(key);
268 if (StringUtils.isBlank(updatedUser.getPassword())
269 || ENCRYPTOR.verify(updatedUser.getPassword(),
270 user.getCipherAlgorithm(), user.getPassword())) {
271
272 updatedUser.setPassword(null);
273 }
274
275 updatedUser.setSecurityQuestion(originalUser.getSecurityQuestion());
276
277 if (!mappingManager.hasMustChangePassword(provision)) {
278 updatedUser.setMustChangePassword(originalUser.isMustChangePassword());
279 }
280
281 anyUR = (U) AnyOperations.diff(updatedUser, originalUser, true);
282 break;
283
284 case "GROUP":
285 GroupTO originalGroup = (GroupTO) original;
286 GroupTO updatedGroup = (GroupTO) updated;
287
288 if (StringUtils.isBlank(updatedGroup.getName())) {
289 updatedGroup.setName(originalGroup.getName());
290 }
291 updatedGroup.setUserOwner(originalGroup.getUserOwner());
292 updatedGroup.setGroupOwner(originalGroup.getGroupOwner());
293 updatedGroup.setUDynMembershipCond(originalGroup.getUDynMembershipCond());
294 updatedGroup.getADynMembershipConds().putAll(originalGroup.getADynMembershipConds());
295 updatedGroup.getTypeExtensions().addAll(originalGroup.getTypeExtensions());
296
297 anyUR = (U) AnyOperations.diff(updatedGroup, originalGroup, true);
298 break;
299
300 default:
301 AnyObjectTO originalAnyObject = (AnyObjectTO) original;
302 AnyObjectTO updatedAnyObject = (AnyObjectTO) updated;
303
304 if (StringUtils.isBlank(updatedAnyObject.getName())) {
305 updatedAnyObject.setName(originalAnyObject.getName());
306 }
307
308 anyUR = (U) AnyOperations.diff(updatedAnyObject, originalAnyObject, true);
309 }
310
311 if (anyUR != null) {
312
313 anyUR.setRealm(null);
314
315
316 AnyOperations.cleanEmptyAttrs(updated, anyUR);
317 }
318 return anyUR;
319 }
320
321 protected <T extends AnyTO> T getAnyTOFromConnObject(
322 final ConnectorObject obj,
323 final PullTask pullTask,
324 final AnyTypeKind anyTypeKind,
325 final Provision provision) {
326
327 T anyTO = anyUtilsFactory.getInstance(anyTypeKind).newAnyTO();
328 anyTO.setType(provision.getAnyType());
329 anyTO.getAuxClasses().addAll(provision.getAuxClasses());
330
331
332 anyTO.setRealm(pullTask.getDestinationRealm().getFullPath());
333 MappingUtils.getPullItems(provision.getMapping().getItems().stream()).forEach(
334 item -> mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO));
335
336
337 templateUtils.apply(anyTO, pullTask.getTemplate(provision.getAnyType()));
338
339 return anyTO;
340 }
341 }