use of org.apache.syncope.core.provisioning.api.Connector in project syncope by apache.
the class AbstractPropagationTaskExecutor method execute.
protected TaskExec execute(final PropagationTaskTO taskTO, final PropagationReporter reporter) {
PropagationTask task = entityFactory.newEntity(PropagationTask.class);
task.setResource(resourceDAO.find(taskTO.getResource()));
task.setObjectClassName(taskTO.getObjectClassName());
task.setAnyTypeKind(taskTO.getAnyTypeKind());
task.setAnyType(taskTO.getAnyType());
task.setEntityKey(taskTO.getEntityKey());
task.setOperation(taskTO.getOperation());
task.setConnObjectKey(taskTO.getConnObjectKey());
task.setOldConnObjectKey(taskTO.getOldConnObjectKey());
Set<Attribute> attributes = new HashSet<>();
if (StringUtils.isNotBlank(taskTO.getAttributes())) {
attributes.addAll(Arrays.asList(POJOHelper.deserialize(taskTO.getAttributes(), Attribute[].class)));
}
task.setAttributes(attributes);
List<PropagationActions> actions = getPropagationActions(task.getResource());
String resource = task.getResource().getKey();
Date start = new Date();
TaskExec execution = entityFactory.newEntity(TaskExec.class);
execution.setStatus(PropagationTaskExecStatus.CREATED.name());
String taskExecutionMessage = null;
String failureReason = null;
// Flag to state whether any propagation has been attempted
AtomicReference<Boolean> propagationAttempted = new AtomicReference<>(false);
ConnectorObject beforeObj = null;
ConnectorObject afterObj = null;
Provision provision = null;
OrgUnit orgUnit = null;
Uid uid = null;
Connector connector = null;
Result result;
try {
provision = task.getResource().getProvision(new ObjectClass(task.getObjectClassName())).orElse(null);
orgUnit = task.getResource().getOrgUnit();
connector = connFactory.getConnector(task.getResource());
// Try to read remote object BEFORE any actual operation
beforeObj = provision == null && orgUnit == null ? null : orgUnit == null ? getRemoteObject(task, connector, provision, false) : getRemoteObject(task, connector, orgUnit, false);
for (PropagationActions action : actions) {
action.before(task, beforeObj);
}
switch(task.getOperation()) {
case CREATE:
case UPDATE:
uid = createOrUpdate(task, beforeObj, connector, propagationAttempted);
break;
case DELETE:
uid = delete(task, beforeObj, connector, propagationAttempted);
break;
default:
}
execution.setStatus(propagationAttempted.get() ? PropagationTaskExecStatus.SUCCESS.name() : PropagationTaskExecStatus.NOT_ATTEMPTED.name());
LOG.debug("Successfully propagated to {}", task.getResource());
result = Result.SUCCESS;
} catch (Exception e) {
result = Result.FAILURE;
LOG.error("Exception during provision on resource " + resource, e);
if (e instanceof ConnectorException && e.getCause() != null) {
taskExecutionMessage = e.getCause().getMessage();
if (e.getCause().getMessage() == null) {
failureReason = e.getMessage();
} else {
failureReason = e.getMessage() + "\n\n Cause: " + e.getCause().getMessage().split("\n")[0];
}
} else {
taskExecutionMessage = ExceptionUtils2.getFullStackTrace(e);
if (e.getCause() == null) {
failureReason = e.getMessage();
} else {
failureReason = e.getMessage() + "\n\n Cause: " + e.getCause().getMessage().split("\n")[0];
}
}
try {
execution.setStatus(PropagationTaskExecStatus.FAILURE.name());
} catch (Exception wft) {
LOG.error("While executing KO action on {}", execution, wft);
}
propagationAttempted.set(true);
actions.forEach(action -> {
action.onError(task, execution, e);
});
} finally {
// Try to read remote object AFTER any actual operation
if (connector != null) {
if (uid != null) {
task.setConnObjectKey(uid.getUidValue());
}
try {
afterObj = provision == null && orgUnit == null ? null : orgUnit == null ? getRemoteObject(task, connector, provision, true) : getRemoteObject(task, connector, orgUnit, true);
} catch (Exception ignore) {
// ignore exception
LOG.error("Error retrieving after object", ignore);
}
}
if (task.getOperation() != ResourceOperation.DELETE && afterObj == null && uid != null) {
afterObj = new ConnectorObjectBuilder().setObjectClass(new ObjectClass(task.getObjectClassName())).setUid(uid).setName(AttributeUtil.getNameFromAttributes(task.getAttributes())).build();
}
execution.setStart(start);
execution.setMessage(taskExecutionMessage);
execution.setEnd(new Date());
LOG.debug("Execution finished: {}", execution);
if (hasToBeregistered(task, execution)) {
LOG.debug("Execution to be stored: {}", execution);
execution.setTask(task);
task.add(execution);
taskDAO.save(task);
// needed to generate a value for the execution key
taskDAO.flush();
}
if (reporter != null) {
reporter.onSuccessOrNonPriorityResourceFailures(taskTO, PropagationTaskExecStatus.valueOf(execution.getStatus()), failureReason, beforeObj, afterObj);
}
}
for (PropagationActions action : actions) {
action.after(task, execution, afterObj);
}
// SYNCOPE-1136
String anyTypeKind = task.getAnyTypeKind() == null ? "realm" : task.getAnyTypeKind().name().toLowerCase();
String operation = task.getOperation().name().toLowerCase();
boolean notificationsAvailable = notificationManager.notificationsAvailable(AuditElements.EventCategoryType.PROPAGATION, anyTypeKind, resource, operation);
boolean auditRequested = auditManager.auditRequested(AuditElements.EventCategoryType.PROPAGATION, anyTypeKind, resource, operation);
if (notificationsAvailable || auditRequested) {
ExecTO execTO = taskDataBinder.getExecTO(execution);
notificationManager.createTasks(AuditElements.EventCategoryType.PROPAGATION, anyTypeKind, resource, operation, result, beforeObj, new Object[] { execTO, afterObj }, taskTO);
auditManager.audit(AuditElements.EventCategoryType.PROPAGATION, anyTypeKind, resource, operation, result, beforeObj, new Object[] { execTO, afterObj }, taskTO);
}
return execution;
}
use of org.apache.syncope.core.provisioning.api.Connector in project syncope by apache.
the class AbstractPropagationTaskExecutor method createOrUpdate.
protected Uid createOrUpdate(final PropagationTask task, final ConnectorObject beforeObj, final Connector connector, final AtomicReference<Boolean> propagationAttempted) {
// set of attributes to be propagated
Set<Attribute> attributes = new HashSet<>(task.getAttributes());
// check if there is any missing or null / empty mandatory attribute
Set<Object> mandatoryAttrNames = new HashSet<>();
Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
if (mandatoryMissing != null) {
attributes.remove(mandatoryMissing);
if (beforeObj == null) {
mandatoryAttrNames.addAll(mandatoryMissing.getValue());
}
}
Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
if (mandatoryNullOrEmpty != null) {
attributes.remove(mandatoryNullOrEmpty);
mandatoryAttrNames.addAll(mandatoryNullOrEmpty.getValue());
}
if (!mandatoryAttrNames.isEmpty()) {
throw new IllegalArgumentException("Not attempted because there are mandatory attributes without value(s): " + mandatoryAttrNames);
}
Uid result;
if (beforeObj == null) {
LOG.debug("Create {} on {}", attributes, task.getResource().getKey());
result = connector.create(new ObjectClass(task.getObjectClassName()), attributes, null, propagationAttempted);
} else {
// 1. check if rename is really required
Name newName = AttributeUtil.getNameFromAttributes(attributes);
LOG.debug("Rename required with value {}", newName);
if (newName != null && newName.equals(beforeObj.getName()) && !newName.getNameValue().equals(beforeObj.getUid().getUidValue())) {
LOG.debug("Remote object name unchanged");
attributes.remove(newName);
}
// 2. check wether anything is actually needing to be propagated, i.e. if there is attribute
// difference between beforeObj - just read above from the connector - and the values to be propagated
Map<String, Attribute> originalAttrMap = beforeObj.getAttributes().stream().collect(Collectors.toMap(attr -> attr.getName().toUpperCase(), attr -> attr));
Map<String, Attribute> updateAttrMap = attributes.stream().collect(Collectors.toMap(attr -> attr.getName().toUpperCase(), attr -> attr));
// Only compare attribute from beforeObj that are also being updated
Set<String> skipAttrNames = originalAttrMap.keySet();
skipAttrNames.removeAll(updateAttrMap.keySet());
new HashSet<>(skipAttrNames).forEach(attrName -> {
originalAttrMap.remove(attrName);
});
Set<Attribute> originalAttrs = new HashSet<>(originalAttrMap.values());
if (originalAttrs.equals(attributes)) {
LOG.debug("Don't need to propagate anything: {} is equal to {}", originalAttrs, attributes);
result = AttributeUtil.getUidAttribute(attributes);
} else {
LOG.debug("Attributes that would be updated {}", attributes);
Set<Attribute> strictlyModified = new HashSet<>();
attributes.stream().filter(attr -> (!originalAttrs.contains(attr))).forEachOrdered(attr -> {
strictlyModified.add(attr);
});
// 3. provision entry
LOG.debug("Update {} on {}", strictlyModified, task.getResource().getKey());
result = connector.update(beforeObj.getObjectClass(), new Uid(beforeObj.getUid().getUidValue()), strictlyModified, null, propagationAttempted);
}
}
return result;
}
use of org.apache.syncope.core.provisioning.api.Connector in project syncope by apache.
the class ResourceLogic method setLatestSyncToken.
@PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
public void setLatestSyncToken(final String key, final String anyTypeKey) {
ExternalResource resource = resourceDAO.authFind(key);
if (resource == null) {
throw new NotFoundException("Resource '" + key + "'");
}
Connector connector;
try {
connector = connFactory.getConnector(resource);
} catch (Exception e) {
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
sce.getElements().add(e.getMessage());
throw sce;
}
if (SyncopeConstants.REALM_ANYTYPE.equals(anyTypeKey)) {
if (resource.getOrgUnit() == null) {
throw new NotFoundException("Realm provision not enabled for Resource '" + key + "'");
}
resource.getOrgUnit().setSyncToken(connector.getLatestSyncToken(resource.getOrgUnit().getObjectClass()));
} else {
AnyType anyType = anyTypeDAO.find(anyTypeKey);
if (anyType == null) {
throw new NotFoundException("AnyType '" + anyTypeKey + "'");
}
Optional<? extends Provision> provision = resource.getProvision(anyType);
if (!provision.isPresent()) {
throw new NotFoundException("Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + "'");
}
provision.get().setSyncToken(connector.getLatestSyncToken(provision.get().getObjectClass()));
}
Set<String> effectiveRealms = RealmUtils.getEffective(AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE), resource.getConnector().getAdminRealm().getFullPath());
securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
resourceDAO.save(resource);
}
use of org.apache.syncope.core.provisioning.api.Connector in project syncope by apache.
the class ResourceLogic method readConnObject.
@PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_GET_CONNOBJECT + "')")
@Transactional(readOnly = true)
public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final String anyKey) {
Triple<ExternalResource, AnyType, Provision> init = connObjectInit(key, anyTypeKey);
// 1. find any
Any<?> any = init.getMiddle().getKind() == AnyTypeKind.USER ? userDAO.find(anyKey) : init.getMiddle().getKind() == AnyTypeKind.ANY_OBJECT ? anyObjectDAO.find(anyKey) : groupDAO.find(anyKey);
if (any == null) {
throw new NotFoundException(init.getMiddle() + " " + anyKey);
}
// 2. build connObjectKeyItem
Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(init.getRight());
if (!connObjectKeyItem.isPresent()) {
throw new NotFoundException("ConnObjectKey mapping for " + init.getMiddle() + " " + anyKey + " on resource '" + key + "'");
}
Optional<String> connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, init.getRight());
// 3. determine attributes to query
Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(init.getRight()).stream().map(virSchema -> virSchema.asLinkingMappingItem()).collect(Collectors.toSet());
Iterator<MappingItem> mapItems = new IteratorChain<>(init.getRight().getMapping().getItems().iterator(), linkinMappingItems.iterator());
// 4. read from the underlying connector
Connector connector = connFactory.getConnector(init.getLeft());
ConnectorObject connectorObject = connector.getObject(init.getRight().getObjectClass(), AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKeyValue.get()), MappingUtils.buildOperationOptions(mapItems));
if (connectorObject == null) {
throw new NotFoundException("Object " + connObjectKeyValue.get() + " with class " + init.getRight().getObjectClass() + " not found on resource " + key);
}
// 5. build result
Set<Attribute> attributes = connectorObject.getAttributes();
if (AttributeUtil.find(Uid.NAME, attributes) == null) {
attributes.add(connectorObject.getUid());
}
if (AttributeUtil.find(Name.NAME, attributes) == null) {
attributes.add(connectorObject.getName());
}
return ConnObjectUtils.getConnObjectTO(connectorObject);
}
use of org.apache.syncope.core.provisioning.api.Connector in project syncope by apache.
the class AbstractPropagationTaskExecutor method getRemoteObject.
/**
* Get remote object for given task.
*
* @param connector connector facade proxy.
* @param task current propagation task.
* @param provision provision
* @param latest 'FALSE' to retrieve object using old connObjectKey if not null.
* @return remote connector object.
*/
protected ConnectorObject getRemoteObject(final PropagationTask task, final Connector connector, final Provision provision, final boolean latest) {
String connObjectKey = latest || task.getOldConnObjectKey() == null ? task.getConnObjectKey() : task.getOldConnObjectKey();
Set<MappingItem> linkingMappingItems = virSchemaDAO.findByProvision(provision).stream().map(schema -> schema.asLinkingMappingItem()).collect(Collectors.toSet());
ConnectorObject obj = null;
Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
if (connObjectKeyItem.isPresent()) {
try {
obj = connector.getObject(new ObjectClass(task.getObjectClassName()), AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey), MappingUtils.buildOperationOptions(new IteratorChain<>(MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(), linkingMappingItems.iterator())));
for (MappingItem item : linkingMappingItems) {
Attribute attr = obj.getAttributeByName(item.getExtAttrName());
if (attr == null) {
virAttrCache.expire(task.getAnyType(), task.getEntityKey(), item.getIntAttrName());
} else {
VirAttrCacheValue cacheValue = new VirAttrCacheValue();
cacheValue.setValues(attr.getValue());
virAttrCache.put(task.getAnyType(), task.getEntityKey(), item.getIntAttrName(), cacheValue);
}
}
} catch (TimeoutException toe) {
LOG.debug("Request timeout", toe);
throw toe;
} catch (RuntimeException ignore) {
LOG.debug("While resolving {}", connObjectKey, ignore);
}
}
return obj;
}
Aggregations