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.pushpull;
20
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Optional;
24 import java.util.Set;
25 import org.apache.commons.lang3.exception.ExceptionUtils;
26 import org.apache.commons.lang3.tuple.Pair;
27 import org.apache.syncope.common.lib.SyncopeClientException;
28 import org.apache.syncope.common.lib.SyncopeConstants;
29 import org.apache.syncope.common.lib.to.OrgUnit;
30 import org.apache.syncope.common.lib.to.ProvisioningReport;
31 import org.apache.syncope.common.lib.to.RealmTO;
32 import org.apache.syncope.common.lib.types.AnyTypeKind;
33 import org.apache.syncope.common.lib.types.AuditElements;
34 import org.apache.syncope.common.lib.types.AuditElements.Result;
35 import org.apache.syncope.common.lib.types.ClientExceptionType;
36 import org.apache.syncope.common.lib.types.MatchingRule;
37 import org.apache.syncope.common.lib.types.PullMode;
38 import org.apache.syncope.common.lib.types.ResourceOperation;
39 import org.apache.syncope.common.lib.types.UnmatchingRule;
40 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
41 import org.apache.syncope.core.persistence.api.dao.CASSPClientAppDAO;
42 import org.apache.syncope.core.persistence.api.dao.OIDCRPClientAppDAO;
43 import org.apache.syncope.core.persistence.api.dao.SAML2SPClientAppDAO;
44 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
45 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
46 import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
47 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
48 import org.apache.syncope.core.persistence.api.entity.Realm;
49 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
50 import org.apache.syncope.core.provisioning.api.PropagationByResource;
51 import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
52 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
53 import org.apache.syncope.core.provisioning.api.pushpull.IgnoreProvisionException;
54 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
55 import org.apache.syncope.core.provisioning.api.pushpull.RealmPullResultHandler;
56 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
57 import org.apache.syncope.core.spring.security.AuthContextUtils;
58 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
59 import org.identityconnectors.framework.common.objects.Attribute;
60 import org.identityconnectors.framework.common.objects.SyncDelta;
61 import org.quartz.JobExecutionException;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.transaction.annotation.Transactional;
64
65 @Transactional(rollbackFor = Throwable.class)
66 public class DefaultRealmPullResultHandler
67 extends AbstractRealmResultHandler<PullTask, PullActions>
68 implements RealmPullResultHandler {
69
70 protected static Result and(final Result left, final Result right) {
71 return left == Result.SUCCESS && right == Result.SUCCESS
72 ? Result.SUCCESS
73 : Result.FAILURE;
74 }
75
76 @Autowired
77 protected InboundMatcher inboundMatcher;
78
79 @Autowired
80 protected ConnObjectUtils connObjectUtils;
81
82 @Autowired
83 protected AnySearchDAO searchDAO;
84
85 @Autowired
86 protected TaskDAO taskDAO;
87
88 @Autowired
89 protected CASSPClientAppDAO casSPClientAppDAO;
90
91 @Autowired
92 protected OIDCRPClientAppDAO oidcRPClientAppDAO;
93
94 @Autowired
95 protected SAML2SPClientAppDAO saml2SPClientAppDAO;
96
97 @Override
98 public boolean handle(final SyncDelta delta) {
99 try {
100 OrgUnit orgUnit = Optional.ofNullable(profile.getTask().getResource().getOrgUnit()).
101 orElseThrow(() -> new JobExecutionException(
102 "No orgUnit found on " + profile.getTask().getResource() + " for "
103 + delta.getObject().getObjectClass()));
104
105 Result latestResult = doHandle(delta, orgUnit);
106
107 LOG.debug("Successfully handled {}", delta);
108
109 if (profile.getTask().getPullMode() != PullMode.INCREMENTAL) {
110 return true;
111 }
112
113 return latestResult == Result.SUCCESS;
114 } catch (IgnoreProvisionException e) {
115 ProvisioningReport ignoreResult = new ProvisioningReport();
116 ignoreResult.setOperation(ResourceOperation.NONE);
117 ignoreResult.setStatus(ProvisioningReport.Status.IGNORE);
118 ignoreResult.setAnyType(SyncopeConstants.REALM_ANYTYPE);
119 ignoreResult.setKey(null);
120 ignoreResult.setName(delta.getObject().getName().getNameValue());
121 profile.getResults().add(ignoreResult);
122
123 LOG.warn("Ignoring during pull", e);
124
125 return true;
126 } catch (JobExecutionException e) {
127 LOG.error("Pull failed", e);
128
129 return false;
130 }
131 }
132
133 protected void throwIgnoreProvisionException(final SyncDelta delta, final Exception exception)
134 throws JobExecutionException {
135
136 if (exception instanceof IgnoreProvisionException) {
137 throw IgnoreProvisionException.class.cast(exception);
138 }
139
140 IgnoreProvisionException ipe = null;
141 for (PullActions action : profile.getActions()) {
142 if (ipe == null) {
143 ipe = action.onError(profile, delta, exception);
144 }
145 }
146 if (ipe != null) {
147 throw ipe;
148 }
149 }
150
151 protected Result assign(final SyncDelta delta, final OrgUnit orgUnit)
152 throws JobExecutionException {
153
154 if (!profile.getTask().isPerformCreate()) {
155 LOG.debug("PullTask not configured for create");
156 end(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta);
157 return Result.SUCCESS;
158 }
159
160 RealmTO realmTO = connObjectUtils.getRealmTO(delta.getObject(), orgUnit);
161 if (realmTO.getFullPath() == null) {
162 if (realmTO.getParent() == null) {
163 realmTO.setParent(profile.getTask().getDestinationRealm().getFullPath());
164 }
165
166 realmTO.setFullPath(realmTO.getParent() + '/' + realmTO.getName());
167 }
168 realmTO.getResources().add(profile.getTask().getResource().getKey());
169
170 ProvisioningReport result = new ProvisioningReport();
171 result.setOperation(ResourceOperation.CREATE);
172 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
173 result.setStatus(ProvisioningReport.Status.SUCCESS);
174 result.setName(realmTO.getFullPath());
175
176 if (profile.isDryRun()) {
177 result.setKey(null);
178 end(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta);
179 return Result.SUCCESS;
180 }
181
182 for (PullActions action : profile.getActions()) {
183 action.beforeAssign(profile, delta, realmTO);
184 }
185
186 profile.getResults().add(result);
187
188 return create(realmTO, delta, UnmatchingRule.ASSIGN, result);
189 }
190
191 protected Result provision(final SyncDelta delta, final OrgUnit orgUnit)
192 throws JobExecutionException {
193
194 if (!profile.getTask().isPerformCreate()) {
195 LOG.debug("PullTask not configured for create");
196 end(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta);
197 return Result.SUCCESS;
198 }
199
200 RealmTO realmTO = connObjectUtils.getRealmTO(delta.getObject(), orgUnit);
201 if (realmTO.getFullPath() == null) {
202 if (realmTO.getParent() == null) {
203 realmTO.setParent(profile.getTask().getDestinationRealm().getFullPath());
204 }
205
206 realmTO.setFullPath(realmTO.getParent() + '/' + realmTO.getName());
207 }
208
209 ProvisioningReport result = new ProvisioningReport();
210 result.setOperation(ResourceOperation.CREATE);
211 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
212 result.setStatus(ProvisioningReport.Status.SUCCESS);
213 result.setName(realmTO.getFullPath());
214
215 if (profile.isDryRun()) {
216 result.setKey(null);
217 end(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta);
218 return Result.SUCCESS;
219 }
220
221 for (PullActions action : profile.getActions()) {
222 action.beforeProvision(profile, delta, realmTO);
223 }
224
225 profile.getResults().add(result);
226
227 return create(realmTO, delta, UnmatchingRule.PROVISION, result);
228 }
229
230 protected Result create(
231 final RealmTO realmTO,
232 final SyncDelta delta,
233 final UnmatchingRule unmatchingRule,
234 final ProvisioningReport result)
235 throws JobExecutionException {
236
237 Object output;
238 Result resultStatus;
239
240 try {
241 Realm realm = realmDAO.save(binder.create(profile.getTask().getDestinationRealm(), realmTO));
242
243 PropagationByResource<String> propByRes = new PropagationByResource<>();
244 propByRes.addAll(ResourceOperation.CREATE, realm.getResourceKeys());
245 if (unmatchingRule == UnmatchingRule.ASSIGN) {
246 List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
247 taskExecutor.execute(taskInfos, false, securityProperties.getAdminUser());
248 }
249
250 RealmTO actual = binder.getRealmTO(realm, true);
251
252 result.setKey(actual.getKey());
253 result.setName(profile.getTask().getDestinationRealm().getFullPath() + '/' + actual.getName());
254
255 output = actual;
256 resultStatus = Result.SUCCESS;
257
258 for (PullActions action : profile.getActions()) {
259 action.after(profile, delta, actual, result);
260 }
261
262 LOG.debug("Realm {} successfully created", actual.getKey());
263 } catch (PropagationException e) {
264
265
266 LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
267 output = e;
268 resultStatus = Result.FAILURE;
269 } catch (Exception e) {
270 throwIgnoreProvisionException(delta, e);
271
272 result.setStatus(ProvisioningReport.Status.FAILURE);
273 result.setMessage(ExceptionUtils.getRootCauseMessage(e));
274 LOG.error("Could not create Realm {} ", delta.getUid().getUidValue(), e);
275 output = e;
276 resultStatus = Result.FAILURE;
277 }
278
279 end(UnmatchingRule.toEventName(unmatchingRule), resultStatus, null, output, delta);
280 return resultStatus;
281 }
282
283 protected Result update(final SyncDelta delta, final List<Realm> realms, final boolean inLink)
284 throws JobExecutionException {
285
286 if (!profile.getTask().isPerformUpdate()) {
287 LOG.debug("PullTask not configured for update");
288 end(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
289 return Result.SUCCESS;
290 }
291
292 LOG.debug("About to update {}", realms);
293
294 Result global = Result.SUCCESS;
295 for (Realm realm : realms) {
296 LOG.debug("About to update {}", realm);
297
298 ProvisioningReport result = new ProvisioningReport();
299 result.setOperation(ResourceOperation.UPDATE);
300 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
301 result.setStatus(ProvisioningReport.Status.SUCCESS);
302 result.setKey(realm.getKey());
303 result.setName(realm.getFullPath());
304
305 if (!profile.isDryRun()) {
306 Result resultStatus;
307 Object output;
308
309 RealmTO before = binder.getRealmTO(realm, true);
310 try {
311 if (!inLink) {
312 for (PullActions action : profile.getActions()) {
313 action.beforeUpdate(profile, delta, before, null);
314 }
315 }
316
317 Map<Pair<String, String>, Set<Attribute>> beforeAttrs = propagationManager.prepareAttrs(realm);
318
319 PropagationByResource<String> propByRes = binder.update(realm, before);
320 realm = realmDAO.save(realm);
321 RealmTO updated = binder.getRealmTO(realm, true);
322
323 List<PropagationTaskInfo> taskInfos = propagationManager.setAttributeDeltas(
324 propagationManager.createTasks(realm, propByRes, null),
325 beforeAttrs,
326 null);
327 taskExecutor.execute(taskInfos, false, securityProperties.getAdminUser());
328
329 for (PullActions action : profile.getActions()) {
330 action.after(profile, delta, updated, result);
331 }
332
333 output = updated;
334 resultStatus = Result.SUCCESS;
335 result.setName(updated.getFullPath());
336
337 LOG.debug("{} successfully updated", updated);
338 } catch (PropagationException e) {
339
340
341 LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
342 output = e;
343 resultStatus = Result.FAILURE;
344 } catch (Exception e) {
345 throwIgnoreProvisionException(delta, e);
346
347 result.setStatus(ProvisioningReport.Status.FAILURE);
348 result.setMessage(ExceptionUtils.getRootCauseMessage(e));
349 LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
350 output = e;
351 resultStatus = Result.FAILURE;
352 }
353
354 end(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
355 global = and(global, resultStatus);
356 }
357
358 profile.getResults().add(result);
359 }
360
361 return global;
362 }
363
364 protected Result deprovision(final SyncDelta delta, final List<Realm> realms, final boolean unlink)
365 throws JobExecutionException {
366
367 if (!profile.getTask().isPerformUpdate()) {
368 LOG.debug("PullTask not configured for update");
369 end(unlink
370 ? MatchingRule.toEventName(MatchingRule.UNASSIGN)
371 : MatchingRule.toEventName(MatchingRule.DEPROVISION), Result.SUCCESS, null, null, delta);
372 return Result.SUCCESS;
373 }
374
375 LOG.debug("About to deprovision {}", realms);
376
377 Result global = Result.SUCCESS;
378 for (Realm realm : realms) {
379 LOG.debug("About to unassign resource {}", realm);
380
381 ProvisioningReport result = new ProvisioningReport();
382 result.setOperation(ResourceOperation.DELETE);
383 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
384 result.setStatus(ProvisioningReport.Status.SUCCESS);
385 result.setKey(realm.getKey());
386 result.setName(realm.getFullPath());
387
388 if (!profile.isDryRun()) {
389 Object output;
390 Result resultStatus;
391
392 RealmTO before = binder.getRealmTO(realm, true);
393 try {
394 if (unlink) {
395 for (PullActions action : profile.getActions()) {
396 action.beforeUnassign(profile, delta, before);
397 }
398 } else {
399 for (PullActions action : profile.getActions()) {
400 action.beforeDeprovision(profile, delta, before);
401 }
402 }
403
404 PropagationByResource<String> propByRes = new PropagationByResource<>();
405 propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
406 taskExecutor.execute(
407 propagationManager.createTasks(realm, propByRes, null),
408 false, securityProperties.getAdminUser());
409
410 RealmTO realmTO;
411 if (unlink) {
412 realm.getResources().remove(profile.getTask().getResource());
413 realmTO = binder.getRealmTO(realmDAO.save(realm), true);
414 } else {
415 realmTO = binder.getRealmTO(realm, true);
416 }
417 output = realmTO;
418
419 for (PullActions action : profile.getActions()) {
420 action.after(profile, delta, realmTO, result);
421 }
422
423 resultStatus = Result.SUCCESS;
424
425 LOG.debug("{} successfully updated", realm);
426 } catch (PropagationException e) {
427
428
429 LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
430 output = e;
431 resultStatus = Result.FAILURE;
432 } catch (Exception e) {
433 throwIgnoreProvisionException(delta, e);
434
435 result.setStatus(ProvisioningReport.Status.FAILURE);
436 result.setMessage(ExceptionUtils.getRootCauseMessage(e));
437 LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
438 output = e;
439 resultStatus = Result.FAILURE;
440 }
441
442 end(unlink
443 ? MatchingRule.toEventName(MatchingRule.UNASSIGN)
444 : MatchingRule.toEventName(MatchingRule.DEPROVISION),
445 resultStatus, before, output, delta);
446 global = and(global, resultStatus);
447 }
448
449 profile.getResults().add(result);
450 }
451
452 return global;
453 }
454
455 protected Result link(final SyncDelta delta, final List<Realm> realms, final boolean unlink)
456 throws JobExecutionException {
457
458 if (!profile.getTask().isPerformUpdate()) {
459 LOG.debug("PullTask not configured for update");
460 end(unlink
461 ? MatchingRule.toEventName(MatchingRule.UNLINK)
462 : MatchingRule.toEventName(MatchingRule.LINK), Result.SUCCESS, null, null, delta);
463 return Result.SUCCESS;
464 }
465
466 LOG.debug("About to link {}", realms);
467
468 Result global = Result.SUCCESS;
469 for (Realm realm : realms) {
470 LOG.debug("About to unassign resource {}", realm);
471
472 ProvisioningReport result = new ProvisioningReport();
473 result.setOperation(ResourceOperation.NONE);
474 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
475 result.setStatus(ProvisioningReport.Status.SUCCESS);
476 result.setKey(realm.getKey());
477 result.setName(realm.getFullPath());
478
479 if (!profile.isDryRun()) {
480 Object output;
481 Result resultStatus;
482
483 RealmTO before = binder.getRealmTO(realm, true);
484 try {
485 if (unlink) {
486 for (PullActions action : profile.getActions()) {
487 action.beforeUnlink(profile, delta, before);
488 }
489 } else {
490 for (PullActions action : profile.getActions()) {
491 action.beforeLink(profile, delta, before);
492 }
493 }
494
495 if (unlink) {
496 realm.getResources().remove(profile.getTask().getResource());
497 } else {
498 realm.add(profile.getTask().getResource());
499 }
500 output = update(delta, List.of(realm), true);
501
502 resultStatus = Result.SUCCESS;
503
504 LOG.debug("{} successfully updated", realm);
505 } catch (PropagationException e) {
506
507
508 LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
509 output = e;
510 resultStatus = Result.FAILURE;
511 } catch (Exception e) {
512 throwIgnoreProvisionException(delta, e);
513
514 result.setStatus(ProvisioningReport.Status.FAILURE);
515 result.setMessage(ExceptionUtils.getRootCauseMessage(e));
516 LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
517 output = e;
518 resultStatus = Result.FAILURE;
519 }
520
521 end(unlink
522 ? MatchingRule.toEventName(MatchingRule.UNLINK)
523 : MatchingRule.toEventName(MatchingRule.LINK),
524 resultStatus, before, output, delta);
525 global = and(global, resultStatus);
526 }
527
528 profile.getResults().add(result);
529 }
530
531 return global;
532 }
533
534 protected Result delete(final SyncDelta delta, final List<Realm> realms)
535 throws JobExecutionException {
536
537 if (!profile.getTask().isPerformDelete()) {
538 LOG.debug("PullTask not configured for delete");
539 end(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
540 return Result.SUCCESS;
541 }
542
543 LOG.debug("About to delete {}", realms);
544
545 Result global = Result.SUCCESS;
546 for (Realm realm : realms) {
547 Object output;
548 Result resultStatus = Result.FAILURE;
549
550 ProvisioningReport result = new ProvisioningReport();
551
552 RealmTO before = binder.getRealmTO(realm, true);
553 try {
554 result.setKey(realm.getKey());
555 result.setName(realm.getFullPath());
556 result.setOperation(ResourceOperation.DELETE);
557 result.setAnyType(SyncopeConstants.REALM_ANYTYPE);
558 result.setStatus(ProvisioningReport.Status.SUCCESS);
559
560 if (!profile.isDryRun()) {
561 for (PullActions action : profile.getActions()) {
562 action.beforeDelete(profile, delta, before);
563 }
564
565 try {
566 if (!realmDAO.findChildren(realm).isEmpty()) {
567 throw SyncopeClientException.build(ClientExceptionType.RealmContains);
568 }
569
570 Set<String> adminRealms = Set.of(realm.getFullPath());
571 AnyCond keyCond = new AnyCond(AttrCond.Type.ISNOTNULL);
572 keyCond.setSchema("key");
573 SearchCond allMatchingCond = SearchCond.getLeaf(keyCond);
574 int users = searchDAO.count(
575 realmDAO.getRoot(), true, adminRealms, allMatchingCond, AnyTypeKind.USER);
576 int groups = searchDAO.count(
577 realmDAO.getRoot(), true, adminRealms, allMatchingCond, AnyTypeKind.GROUP);
578 int anyObjects = searchDAO.count(
579 realmDAO.getRoot(), true, adminRealms, allMatchingCond, AnyTypeKind.ANY_OBJECT);
580 int macroTasks = taskDAO.findByRealm(realm).size();
581 int clientApps = casSPClientAppDAO.findByRealm(realm).size()
582 + saml2SPClientAppDAO.findByRealm(realm).size()
583 + oidcRPClientAppDAO.findByRealm(realm).size();
584
585 if (users + groups + anyObjects + macroTasks + clientApps > 0) {
586 SyncopeClientException realmContains =
587 SyncopeClientException.build(ClientExceptionType.RealmContains);
588 realmContains.getElements().add(users + " user(s)");
589 realmContains.getElements().add(groups + " group(s)");
590 realmContains.getElements().add(anyObjects + " anyObject(s)");
591 realmContains.getElements().add(macroTasks + " command task(s)");
592 realmContains.getElements().add(clientApps + " client app(s)");
593 throw realmContains;
594 }
595
596 PropagationByResource<String> propByRes = new PropagationByResource<>();
597 propByRes.addAll(ResourceOperation.DELETE, realm.getResourceKeys());
598 List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
599 taskExecutor.execute(taskInfos, false, securityProperties.getAdminUser());
600
601 realmDAO.delete(realm);
602
603 output = null;
604 resultStatus = Result.SUCCESS;
605
606 for (PullActions action : profile.getActions()) {
607 action.after(profile, delta, before, result);
608 }
609 } catch (Exception e) {
610 throwIgnoreProvisionException(delta, e);
611
612 result.setStatus(ProvisioningReport.Status.FAILURE);
613 result.setMessage(ExceptionUtils.getRootCauseMessage(e));
614 LOG.error("Could not delete {}", realm, e);
615 output = e;
616 }
617
618 end(ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, delta);
619 global = and(global, resultStatus);
620 }
621
622 profile.getResults().add(result);
623 } catch (DelegatedAdministrationException e) {
624 LOG.error("Not allowed to read Realm {}", realm, e);
625 } catch (Exception e) {
626 LOG.error("Could not delete Realm {}", realm, e);
627 }
628 }
629
630 return global;
631 }
632
633 protected Result ignore(final SyncDelta delta, final boolean matching) throws JobExecutionException {
634 LOG.debug("Any to ignore {}", delta.getObject().getUid().getUidValue());
635
636 ProvisioningReport report = new ProvisioningReport();
637 report.setKey(null);
638 report.setName(delta.getObject().getUid().getUidValue());
639 report.setOperation(ResourceOperation.NONE);
640 report.setAnyType(SyncopeConstants.REALM_ANYTYPE);
641 report.setStatus(ProvisioningReport.Status.SUCCESS);
642 profile.getResults().add(report);
643
644 if (!profile.isDryRun()) {
645 end(matching
646 ? MatchingRule.toEventName(MatchingRule.IGNORE)
647 : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta);
648 return Result.SUCCESS;
649 }
650
651 return Result.SUCCESS;
652 }
653
654 protected Result doHandle(final SyncDelta delta, final OrgUnit orgUnit) throws JobExecutionException {
655 LOG.debug("Process {} for {} as {}",
656 delta.getDeltaType(), delta.getUid().getUidValue(), delta.getObject().getObjectClass());
657
658 SyncDelta finalDelta = delta;
659 for (PullActions action : profile.getActions()) {
660 finalDelta = action.preprocess(profile, finalDelta);
661 }
662
663 LOG.debug("Transformed {} for {} as {}",
664 finalDelta.getDeltaType(), finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass());
665
666 List<Realm> realms = inboundMatcher.match(finalDelta, orgUnit);
667 LOG.debug("Match found for {} as {}: {}",
668 finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass(), realms);
669
670 if (realms.size() > 1) {
671 switch (profile.getConflictResolutionAction()) {
672 case IGNORE:
673 throw new IgnoreProvisionException("More than one match found for "
674 + finalDelta.getObject().getUid().getUidValue() + ": " + realms);
675
676 case FIRSTMATCH:
677 realms = realms.subList(0, 1);
678 break;
679
680 case LASTMATCH:
681 realms = realms.subList(realms.size() - 1, realms.size());
682 break;
683
684 default:
685
686 }
687 }
688
689 Result result = Result.SUCCESS;
690 try {
691 switch (delta.getDeltaType()) {
692 case CREATE:
693 case UPDATE:
694 case CREATE_OR_UPDATE:
695 if (realms.isEmpty()) {
696 switch (profile.getTask().getUnmatchingRule()) {
697 case ASSIGN:
698 result = assign(finalDelta, orgUnit);
699 break;
700
701 case PROVISION:
702 result = provision(finalDelta, orgUnit);
703 break;
704
705 case IGNORE:
706 result = ignore(finalDelta, false);
707 break;
708
709 default:
710
711 }
712 } else {
713 switch (profile.getTask().getMatchingRule()) {
714 case UPDATE:
715 result = update(finalDelta, realms, false);
716 break;
717
718 case DEPROVISION:
719 result = deprovision(finalDelta, realms, false);
720 break;
721
722 case UNASSIGN:
723 result = deprovision(finalDelta, realms, true);
724 break;
725
726 case LINK:
727 result = link(finalDelta, realms, false);
728 break;
729
730 case UNLINK:
731 result = link(finalDelta, realms, true);
732 break;
733
734 case IGNORE:
735 result = ignore(finalDelta, true);
736 break;
737
738 default:
739
740 }
741 }
742 break;
743
744 case DELETE:
745 if (realms.isEmpty()) {
746 end(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, finalDelta);
747 LOG.debug("No match found for deletion");
748 } else {
749 result = delete(finalDelta, realms);
750 }
751 break;
752
753 default:
754 }
755 } catch (IllegalStateException | IllegalArgumentException e) {
756 LOG.warn(e.getMessage());
757 }
758
759 return result;
760 }
761
762 protected void end(
763 final String event,
764 final Result result,
765 final Object before,
766 final Object output,
767 final SyncDelta delta) {
768
769 notificationManager.createTasks(
770 AuthContextUtils.getWho(),
771 AuditElements.EventCategoryType.PULL,
772 SyncopeConstants.REALM_ANYTYPE.toLowerCase(),
773 profile.getTask().getResource().getKey(),
774 event,
775 result,
776 before,
777 output,
778 delta);
779
780 auditManager.audit(
781 AuthContextUtils.getWho(),
782 AuditElements.EventCategoryType.PULL,
783 SyncopeConstants.REALM_ANYTYPE.toLowerCase(),
784 profile.getTask().getResource().getKey(),
785 event,
786 result,
787 before,
788 output,
789 delta);
790 }
791 }