From fbc65fdd3e6635825d9f5bbba82f7ceb2cfdae83 Mon Sep 17 00:00:00 2001 From: Andrea Patricelli Date: Thu, 9 Jan 2025 17:47:27 +0100 Subject: [PATCH] [SCIM-34] better attribute delta management (#104) --- .../scim/common/AbstractSCIMConnector.java | 3 +- .../bundles/scim/v11/SCIMv11Connector.java | 4 +- .../bundles/scim/v2/SCIMv2Connector.java | 58 ++++++++++++------- .../bundles/scim/v2/dto/SCIMv2Patch.java | 3 + .../bundles/scim/v2/dto/SCIMv2PatchImpl.java | 6 ++ 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/main/java/net/tirasa/connid/bundles/scim/common/AbstractSCIMConnector.java b/src/main/java/net/tirasa/connid/bundles/scim/common/AbstractSCIMConnector.java index 2c485bd..ff88682 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/common/AbstractSCIMConnector.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/common/AbstractSCIMConnector.java @@ -765,7 +765,8 @@ protected abstract void fillGroupPatches( protected abstract P buildGroupPatch(Set modifications); - protected abstract PO buildPatchOperation(AttributeDelta currentDelta, SCIMBaseAttribute attributeDefinition); + protected abstract List buildPatchOperations( + AttributeDelta currentDelta, SCIMBaseAttribute attributeDefinition); protected abstract List buildGroupPatchOperations(Set modifications); diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v11/SCIMv11Connector.java b/src/main/java/net/tirasa/connid/bundles/scim/v11/SCIMv11Connector.java index d2b050c..9564d36 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v11/SCIMv11Connector.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v11/SCIMv11Connector.java @@ -145,8 +145,10 @@ protected SCIMv11BasePatch buildGroupPatch(final Set modificatio } @Override - protected SCIMPatchOperation buildPatchOperation(final AttributeDelta currentDelta, + protected List buildPatchOperations( + final AttributeDelta currentDelta, final SCIMBaseAttribute attributeDefinition) { + throw new ConnectorException("Update delta is not supported in version 1.1"); } diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v2/SCIMv2Connector.java b/src/main/java/net/tirasa/connid/bundles/scim/v2/SCIMv2Connector.java index dab6e71..46d1d2d 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v2/SCIMv2Connector.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v2/SCIMv2Connector.java @@ -187,7 +187,7 @@ protected SCIMv2Patch buildUserPatch( } else if (!attrDelta.getName().contains(SCIMAttributeUtils.SCIM_USER_ADDRESSES) && !attrDelta.is(SCIMAttributeUtils.SCIM_USER_GROUPS)) { - patch.addOperation(buildPatchOperation(attrDelta, null)); + patch.addOperations(buildPatchOperations(attrDelta, null)); } } // manage addresses patches @@ -195,7 +195,10 @@ protected SCIMv2Patch buildUserPatch( // custom attributes if (StringUtil.isNotBlank(configuration.getCustomAttributesJSON())) { - buildCustomAttributesPatchOperations(modifications).forEach(patch::addOperation); + buildCustomAttributesPatchOperations( + modifications, + configuration.getUseColonOnExtensionAttributes()). + forEach(patch::addOperation); } // manage groups if (manageGroups) { @@ -220,7 +223,7 @@ protected SCIMv2Patch buildGroupPatch(final Set modifications) { .value(attrDelta.getValuesToReplace().get(0)) .build()); } else if (!attrDelta.getName().contains(SCIMAttributeUtils.SCIM_GROUP_MEMBERS)) { - patch.addOperation(buildPatchOperation(attrDelta, null)); + patch.addOperations(buildPatchOperations(attrDelta, null)); } } @@ -280,51 +283,64 @@ protected SCIMv2Patch buildGroupPatch(final Set modifications) { return patch; } - protected List buildCustomAttributesPatchOperations(final Set modifications) { + protected List buildCustomAttributesPatchOperations( + final Set modifications, + final boolean useColon) { + List operations = new ArrayList<>(); SCIMUtils.extractSCIMSchemas(configuration.getCustomAttributesJSON(), SCIMv2Attribute.class).ifPresent( scimSchema -> { for (SCIMv2Attribute customAttribute : scimSchema.getAttributes()) { String extAttrName = SCIMv2Attribute.class.cast(customAttribute).getExtensionSchema(). - concat(".").concat(customAttribute.getName()); + concat(useColon ? ":" : ".").concat(customAttribute.getName()); // only single valued attributes are supported - modifications.stream().filter(mod -> mod.getName().equals(extAttrName)) - .findFirst().ifPresent(ad -> buildPatchOperation(ad, customAttribute)); + modifications.stream().filter(mod -> mod.getName().equals(extAttrName)).findFirst() + .ifPresent(ad -> operations.addAll(buildPatchOperations(ad, customAttribute))); } }); return operations; } @Override - protected SCIMv2PatchOperation buildPatchOperation( + protected List buildPatchOperations( final AttributeDelta currentDelta, final SCIMBaseAttribute attributeDefinition) { - SCIMv2PatchOperation patchOperation = new SCIMv2PatchOperation(); - patchOperation.setPath(SCIMAttributeUtils.getBaseAttributeName(currentDelta.getName())); + List operations = new ArrayList<>(); + if (CollectionUtil.isEmpty(currentDelta.getValuesToReplace())) { if (!CollectionUtil.isEmpty(currentDelta.getValuesToAdd())) { - patchOperation.setOp(SCIMAttributeUtils.SCIM_ADD); - patchOperation.setValue( + SCIMv2PatchOperation addPatchOperation = new SCIMv2PatchOperation(); + addPatchOperation.setPath(SCIMAttributeUtils.getBaseAttributeName(currentDelta.getName())); + addPatchOperation.setOp(SCIMAttributeUtils.SCIM_ADD); + addPatchOperation.setValue( buildPatchValue(currentDelta.getName(), currentDelta.getValuesToAdd(), attributeDefinition)); + operations.add(addPatchOperation); } - if (CollectionUtil.isEmpty(currentDelta.getValuesToAdd()) - && !CollectionUtil.isEmpty(currentDelta.getValuesToRemove())) { - patchOperation.setOp(SCIMAttributeUtils.SCIM_REMOVE); + // also add values to remove in a new operation, if any + if (!CollectionUtil.isEmpty(currentDelta.getValuesToRemove())) { + SCIMv2PatchOperation removePatchOperation = new SCIMv2PatchOperation(); + removePatchOperation.setOp(SCIMAttributeUtils.SCIM_REMOVE); // while removing specific attribute values we must use a filter like emails[value eq \"user // .secondary@example.com\"], if multiple values are present must filter in OR like // emails[value eq \"user.secondary@example.com\" or value eq \"user.tertiary@example.com\"] - patchOperation.setPath( - buildFilteredPath(currentDelta.getName(), currentDelta.getValuesToRemove(), "or", "eq")); - patchOperation.setValue( + removePatchOperation.setPath( + buildFilteredPath(SCIMAttributeUtils.getBaseAttributeName(currentDelta.getName()), + currentDelta.getValuesToRemove(), "or", "eq")); + removePatchOperation.setValue( buildPatchValue(currentDelta.getName(), currentDelta.getValuesToRemove(), attributeDefinition)); + operations.add(removePatchOperation); } } else { - patchOperation.setOperation(SCIMAttributeUtils.SCIM_REPLACE); - patchOperation.setValue( + SCIMv2PatchOperation replacePatchOperation = new SCIMv2PatchOperation(); + replacePatchOperation.setPath(SCIMAttributeUtils.getBaseAttributeName(currentDelta.getName())); + replacePatchOperation.setOperation(SCIMAttributeUtils.SCIM_REPLACE); + replacePatchOperation.setValue( buildPatchValue(currentDelta.getName(), currentDelta.getValuesToReplace(), attributeDefinition)); + operations.add(replacePatchOperation); } - return patchOperation; + + return operations; } @Override diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2Patch.java b/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2Patch.java index 106af3b..15db92c 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2Patch.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2Patch.java @@ -15,6 +15,7 @@ */ package net.tirasa.connid.bundles.scim.v2.dto; +import java.util.List; import java.util.Set; import net.tirasa.connid.bundles.scim.common.dto.SCIMBasePatch; @@ -23,5 +24,7 @@ public interface SCIMv2Patch extends SCIMBasePatch { Set getOperations(); void addOperation(SCIMv2PatchOperation operation); + + void addOperations(List operations); } diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2PatchImpl.java b/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2PatchImpl.java index f5f72ec..015b4d5 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2PatchImpl.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v2/dto/SCIMv2PatchImpl.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -70,6 +71,11 @@ public void addOperation(final SCIMv2PatchOperation operation) { this.operations.add(operation); } + @Override + public void addOperations(final List operations) { + this.operations.addAll(operations); + } + @Override public String toString() { return "SCIMv2Patch{"