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.util.Collection;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28 import org.apache.commons.lang3.tuple.Pair;
29 import org.apache.syncope.common.lib.request.PasswordPatch;
30 import org.apache.syncope.common.lib.request.StatusR;
31 import org.apache.syncope.common.lib.request.StringPatchItem;
32 import org.apache.syncope.common.lib.request.UserCR;
33 import org.apache.syncope.common.lib.request.UserUR;
34 import org.apache.syncope.common.lib.to.PropagationStatus;
35 import org.apache.syncope.common.lib.to.ProvisioningReport;
36 import org.apache.syncope.common.lib.types.AnyTypeKind;
37 import org.apache.syncope.common.lib.types.PatchOperation;
38 import org.apache.syncope.common.lib.types.ResourceOperation;
39 import org.apache.syncope.common.lib.types.StatusRType;
40 import org.apache.syncope.core.persistence.api.dao.UserDAO;
41 import org.apache.syncope.core.provisioning.api.PropagationByResource;
42 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
43 import org.apache.syncope.core.provisioning.api.UserWorkflowResult;
44 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
45 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
46 import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
47 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
48 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
49 import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
50 import org.identityconnectors.framework.common.objects.Attribute;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53 import org.springframework.transaction.annotation.Propagation;
54 import org.springframework.transaction.annotation.Transactional;
55
56 public class DefaultUserProvisioningManager implements UserProvisioningManager {
57
58 protected static final Logger LOG = LoggerFactory.getLogger(UserProvisioningManager.class);
59
60 protected final UserWorkflowAdapter uwfAdapter;
61
62 protected final PropagationManager propagationManager;
63
64 protected final PropagationTaskExecutor taskExecutor;
65
66 protected final UserDAO userDAO;
67
68 protected final VirAttrHandler virtAttrHandler;
69
70 public DefaultUserProvisioningManager(
71 final UserWorkflowAdapter uwfAdapter,
72 final PropagationManager propagationManager,
73 final PropagationTaskExecutor taskExecutor,
74 final UserDAO userDAO,
75 final VirAttrHandler virtAttrHandler) {
76
77 this.uwfAdapter = uwfAdapter;
78 this.propagationManager = propagationManager;
79 this.taskExecutor = taskExecutor;
80 this.userDAO = userDAO;
81 this.virtAttrHandler = virtAttrHandler;
82 }
83
84 @Override
85 public Pair<String, List<PropagationStatus>> create(
86 final UserCR userCR, final boolean nullPriorityAsync, final String creator, final String context) {
87
88 return create(userCR, false, null, Set.of(), nullPriorityAsync, creator, context);
89 }
90
91 @Transactional(propagation = Propagation.REQUIRES_NEW)
92 @Override
93 public Pair<String, List<PropagationStatus>> create(
94 final UserCR userCR,
95 final boolean disablePwdPolicyCheck,
96 final Boolean enabled,
97 final Set<String> excludedResources,
98 final boolean nullPriorityAsync,
99 final String creator,
100 final String context) {
101
102 UserWorkflowResult<Pair<String, Boolean>> created =
103 uwfAdapter.create(userCR, disablePwdPolicyCheck, enabled, creator, context);
104
105 List<PropagationTaskInfo> taskInfos = propagationManager.getUserCreateTasks(
106 created.getResult().getLeft(),
107 userCR.getPassword(),
108 created.getResult().getRight(),
109 created.getPropByRes(),
110 created.getPropByLinkedAccount(),
111 userCR.getVirAttrs(),
112 excludedResources);
113 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, creator);
114
115 return Pair.of(created.getResult().getLeft(), propagationReporter.getStatuses());
116 }
117
118 @Override
119 public Pair<UserUR, List<PropagationStatus>> update(
120 final UserUR userUR, final boolean nullPriorityAsync, final String updater, final String context) {
121
122 Map<Pair<String, String>, Set<Attribute>> beforeAttrs = propagationManager.prepareAttrs(
123 AnyTypeKind.USER,
124 userUR.getKey(),
125 Optional.ofNullable(userUR.getPassword()).map(PasswordPatch::getValue).orElse(null),
126 userUR.getPassword() != null,
127 null,
128 Set.of());
129
130 UserWorkflowResult<Pair<UserUR, Boolean>> updated = uwfAdapter.update(userUR, null, updater, context);
131
132 List<PropagationTaskInfo> taskInfos = propagationManager.setAttributeDeltas(
133 propagationManager.getUserUpdateTasks(updated),
134 beforeAttrs,
135 updated.getResult().getLeft());
136 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, updater);
137
138 return Pair.of(updated.getResult().getLeft(), propagationReporter.getStatuses());
139 }
140
141 @Override
142 public Pair<UserUR, List<PropagationStatus>> update(
143 final UserUR userUR,
144 final Set<String> excludedResources,
145 final boolean nullPriorityAsync,
146 final String updater,
147 final String context) {
148
149 return update(userUR, new ProvisioningReport(), null, excludedResources, nullPriorityAsync, updater, context);
150 }
151
152 @Transactional(propagation = Propagation.REQUIRES_NEW)
153 @Override
154 public Pair<UserUR, List<PropagationStatus>> update(
155 final UserUR userUR,
156 final ProvisioningReport result,
157 final Boolean enabled,
158 final Set<String> excludedResources,
159 final boolean nullPriorityAsync,
160 final String updater,
161 final String context) {
162
163 Map<Pair<String, String>, Set<Attribute>> beforeAttrs = propagationManager.prepareAttrs(
164 AnyTypeKind.USER,
165 userUR.getKey(),
166 Optional.ofNullable(userUR.getPassword()).map(PasswordPatch::getValue).orElse(null),
167 userUR.getPassword() != null,
168 enabled,
169 excludedResources);
170
171 UserWorkflowResult<Pair<UserUR, Boolean>> updated;
172 try {
173 updated = uwfAdapter.update(userUR, enabled, updater, context);
174 } catch (Exception e) {
175 LOG.error("Update of user {} failed, trying to pull its status anyway (if configured)",
176 userUR.getKey(), e);
177
178 result.setStatus(ProvisioningReport.Status.FAILURE);
179 result.setMessage("Update failed, trying to pull status anyway (if configured)\n" + e.getMessage());
180
181 updated = new UserWorkflowResult<>(
182 Pair.of(userUR, false),
183 new PropagationByResource<>(),
184 new PropagationByResource<>(),
185 new HashSet<>());
186 }
187
188 List<PropagationTaskInfo> taskInfos = propagationManager.setAttributeDeltas(
189 propagationManager.getUserUpdateTasks(
190 updated,
191 updated.getResult().getLeft().getPassword() != null,
192 excludedResources),
193 beforeAttrs,
194 updated.getResult().getLeft());
195 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, updater);
196
197 return Pair.of(updated.getResult().getLeft(), propagationReporter.getStatuses());
198 }
199
200 @Override
201 public List<PropagationStatus> delete(
202 final String key, final boolean nullPriorityAsync, final String eraser, final String context) {
203
204 return delete(key, Set.of(), nullPriorityAsync, eraser, context);
205 }
206
207 @Transactional(propagation = Propagation.REQUIRES_NEW)
208 @Override
209 public List<PropagationStatus> delete(
210 final String key,
211 final Set<String> excludedResources,
212 final boolean nullPriorityAsync,
213 final String eraser,
214 final String context) {
215
216 PropagationByResource<String> propByRes = new PropagationByResource<>();
217 propByRes.set(ResourceOperation.DELETE, userDAO.findAllResourceKeys(key));
218
219 PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>();
220 userDAO.findLinkedAccounts(key).forEach(account -> propByLinkedAccount.add(
221 ResourceOperation.DELETE,
222 Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue())));
223
224
225
226
227
228
229 List<PropagationTaskInfo> taskInfos = propagationManager.getDeleteTasks(
230 AnyTypeKind.USER,
231 key,
232 propByRes,
233 propByLinkedAccount,
234 excludedResources);
235 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, eraser);
236
237 uwfAdapter.delete(key, eraser, context);
238
239 return propagationReporter.getStatuses();
240 }
241
242 @Override
243 public String unlink(final UserUR userUR, final String updater, final String context) {
244 UserWorkflowResult<Pair<UserUR, Boolean>> updated = uwfAdapter.update(userUR, null, updater, context);
245 return updated.getResult().getLeft().getKey();
246 }
247
248 @Override
249 public String link(final UserUR userUR, final String updater, final String context) {
250 return uwfAdapter.update(userUR, null, updater, context).getResult().getLeft().getKey();
251 }
252
253 @Override
254 public Pair<String, List<PropagationStatus>> activate(
255 final StatusR statusR, final boolean nullPriorityAsync, final String updater, final String context) {
256
257 UserWorkflowResult<String> updated = statusR.isOnSyncope()
258 ? uwfAdapter.activate(statusR.getKey(), statusR.getToken(), updater, context)
259 : new UserWorkflowResult<>(statusR.getKey(), null, null, statusR.getType().name().toLowerCase());
260
261 return Pair.of(updated.getResult(), propagateStatus(statusR, nullPriorityAsync, updater));
262 }
263
264 @Override
265 public Pair<String, List<PropagationStatus>> reactivate(
266 final StatusR statusR, final boolean nullPriorityAsync, final String updater, final String context) {
267
268 UserWorkflowResult<String> updated = statusR.isOnSyncope()
269 ? uwfAdapter.reactivate(statusR.getKey(), updater, context)
270 : new UserWorkflowResult<>(statusR.getKey(), null, null, statusR.getType().name().toLowerCase());
271
272 return Pair.of(updated.getResult(), propagateStatus(statusR, nullPriorityAsync, updater));
273 }
274
275 @Override
276 public Pair<String, List<PropagationStatus>> suspend(
277 final StatusR statusR, final boolean nullPriorityAsync, final String updater, final String context) {
278
279 UserWorkflowResult<String> updated = statusR.isOnSyncope()
280 ? uwfAdapter.suspend(statusR.getKey(), updater, context)
281 : new UserWorkflowResult<>(statusR.getKey(), null, null, statusR.getType().name().toLowerCase());
282
283 return Pair.of(updated.getResult(), propagateStatus(statusR, nullPriorityAsync, updater));
284 }
285
286 protected List<PropagationStatus> propagateStatus(
287 final StatusR statusR, final boolean nullPriorityAsync, final String updater) {
288
289 PropagationByResource<String> propByRes = new PropagationByResource<>();
290 propByRes.addAll(ResourceOperation.UPDATE, statusR.getResources());
291 List<PropagationTaskInfo> taskInfos = propagationManager.getUpdateTasks(
292 AnyTypeKind.USER,
293 statusR.getKey(),
294 false,
295 statusR.getType() != StatusRType.SUSPEND,
296 propByRes,
297 null,
298 null,
299 null);
300 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, updater);
301
302 return propagationReporter.getStatuses();
303 }
304
305 @Override
306 public void internalSuspend(final String key, final String updater, final String context) {
307 Pair<UserWorkflowResult<String>, Boolean> updated = uwfAdapter.internalSuspend(key, updater, context);
308
309
310 if (updated != null && updated.getRight()) {
311 UserUR userUR = new UserUR();
312 userUR.setKey(updated.getLeft().getResult());
313
314 List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(new UserWorkflowResult<>(
315 Pair.of(userUR, Boolean.FALSE),
316 updated.getLeft().getPropByRes(),
317 updated.getLeft().getPropByLinkedAccount(),
318 updated.getLeft().getPerformedTasks()));
319 taskExecutor.execute(taskInfos, false, updater);
320 }
321 }
322
323 @Override
324 public List<PropagationStatus> provision(
325 final String key,
326 final boolean changePwd,
327 final String password,
328 final Collection<String> resources,
329 final boolean nullPriorityAsync,
330 final String executor) {
331
332 UserUR userUR = new UserUR();
333 userUR.setKey(key);
334 userUR.getResources().addAll(resources.stream().
335 map(r -> new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(r).build()).
336 collect(Collectors.toSet()));
337
338 if (changePwd) {
339 PasswordPatch passwordPatch = new PasswordPatch();
340 passwordPatch.setOnSyncope(false);
341 passwordPatch.getResources().addAll(resources);
342 passwordPatch.setValue(password);
343 userUR.setPassword(passwordPatch);
344 }
345
346 PropagationByResource<String> propByRes = new PropagationByResource<>();
347 propByRes.addAll(ResourceOperation.UPDATE, resources);
348
349 UserWorkflowResult<Pair<UserUR, Boolean>> wfResult = new UserWorkflowResult<>(
350 Pair.of(userUR, (Boolean) null), propByRes, null, "update");
351
352 List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(wfResult, changePwd, null);
353 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, executor);
354
355 return propagationReporter.getStatuses();
356 }
357
358 @Override
359 public List<PropagationStatus> deprovision(
360 final String key,
361 final Collection<String> resources,
362 final boolean nullPriorityAsync,
363 final String executor) {
364
365 PropagationByResource<String> propByRes = new PropagationByResource<>();
366 propByRes.set(ResourceOperation.DELETE, resources);
367
368 PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>();
369 userDAO.findLinkedAccounts(key).stream().
370 filter(account -> resources.contains(account.getResource().getKey())).
371 forEach(account -> propByLinkedAccount.add(
372 ResourceOperation.DELETE,
373 Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue())));
374
375 List<PropagationTaskInfo> taskInfos = propagationManager.getDeleteTasks(
376 AnyTypeKind.USER,
377 key,
378 propByRes,
379 propByLinkedAccount,
380 userDAO.findAllResourceKeys(key).stream().
381 filter(resource -> !resources.contains(resource)).
382 collect(Collectors.toList()));
383 PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, executor);
384
385 return propagationReporter.getStatuses();
386 }
387
388 @Override
389 public void requestPasswordReset(final String key, final String updater, final String context) {
390 uwfAdapter.requestPasswordReset(key, updater, context);
391 }
392
393 @Override
394 public void confirmPasswordReset(
395 final String key, final String token, final String password, final String updater, final String context) {
396
397 UserWorkflowResult<Pair<UserUR, Boolean>> updated =
398 uwfAdapter.confirmPasswordReset(key, token, password, updater, context);
399
400 List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(updated);
401 taskExecutor.execute(taskInfos, false, updater);
402 }
403 }