This is an automated email from the ASF dual-hosted git repository.

andreapatricelli pushed a commit to branch 4_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_0_X by this push:
     new 93fc7802b8 [SYNCOPE-1894] adding support to attributes with dot on 
resource mapping (#1137)
93fc7802b8 is described below

commit 93fc7802b81095235bc1dbfbfd6d4572a00a1a93
Author: Andrea Patricelli <andreapatrice...@apache.org>
AuthorDate: Thu Jul 17 13:27:26 2025 +0200

    [SYNCOPE-1894] adding support to attributes with dot on resource mapping 
(#1137)
---
 .../core/provisioning/api/IntAttrNameParser.java   | 21 ++++++----
 .../provisioning/api/IntAttrNameParserTest.java    | 11 ++++-
 .../apache/syncope/fit/core/UserIssuesITCase.java  | 47 ++++++++++++++++++++++
 3 files changed, 70 insertions(+), 9 deletions(-)

diff --git 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrNameParser.java
 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrNameParser.java
index 745525f2f0..be93020834 100644
--- 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrNameParser.java
+++ 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrNameParser.java
@@ -22,6 +22,7 @@ import java.text.ParseException;
 import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -36,23 +37,26 @@ import 
org.springframework.transaction.annotation.Transactional;
 @SuppressWarnings({ "squid:S4784", "squid:S3776" })
 public class IntAttrNameParser {
 
-    protected static final String END_PATTERN = ")\\]\\.(.+)";
+    protected static final String END_PATTERN = "\\]\\.(.+)";
 
     protected static final Pattern ENCLOSING_GROUP_PATTERN = Pattern.compile(
-            "^groups\\[(" + Entity.ID_REGEX + END_PATTERN);
+            "^groups\\[(" + Entity.ID_REGEX + ")" + END_PATTERN);
 
     protected static final Pattern RELATED_USER_PATTERN = Pattern.compile(
-            "^users\\[(" + Entity.ID_REGEX + END_PATTERN);
+            "^users\\[(" + Entity.ID_REGEX + ")" + END_PATTERN);
 
     protected static final Pattern RELATED_ANY_OBJECT_PATTERN = 
Pattern.compile(
-            "^anyObjects\\[(" + Entity.ID_REGEX + END_PATTERN);
+            "^anyObjects\\[(" + Entity.ID_REGEX + ")" + END_PATTERN);
 
     protected static final Pattern MEMBERSHIP_PATTERN = Pattern.compile(
-            "^memberships\\[(" + Entity.ID_REGEX + END_PATTERN);
+            "^memberships\\[(" + Entity.ID_REGEX + ")" + END_PATTERN);
 
     protected static final Pattern RELATIONSHIP_PATTERN = Pattern.compile(
             "^relationships\\[(" + Entity.ID_REGEX + ")\\]"
-            + "\\[(" + Entity.ID_REGEX + END_PATTERN);
+            + "\\[(" + Entity.ID_REGEX + ")" + END_PATTERN);
+
+    protected static final CharSequence[] RESERVED_WORDS =
+            { "groups", "users", "anyObjects", "memberships", "relationships" 
};
 
     protected final PlainSchemaDAO plainSchemaDAO;
 
@@ -103,11 +107,12 @@ public class IntAttrNameParser {
     public IntAttrName parse(final String intAttrName, final AnyTypeKind 
provisionAnyTypeKind) throws ParseException {
         IntAttrName result = new IntAttrName();
 
-        if (intAttrName.indexOf('.') == -1) {
+        Matcher matcher = Pattern.compile(END_PATTERN).matcher(intAttrName);
+        if (!matcher.matches() && !StringUtils.containsAny(intAttrName, 
RESERVED_WORDS)) {
             result.setAnyTypeKind(provisionAnyTypeKind);
             setFieldOrSchemaName(intAttrName, result.getAnyTypeKind(), result);
         } else {
-            Matcher matcher = ENCLOSING_GROUP_PATTERN.matcher(intAttrName);
+            matcher = ENCLOSING_GROUP_PATTERN.matcher(intAttrName);
             if (matcher.matches()) {
                 result.setAnyTypeKind(AnyTypeKind.GROUP);
                 result.setEnclosingGroup(matcher.group(1));
diff --git 
a/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/IntAttrNameParserTest.java
 
b/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/IntAttrNameParserTest.java
index 5823218fb3..fd7569e071 100644
--- 
a/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/IntAttrNameParserTest.java
+++ 
b/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/IntAttrNameParserTest.java
@@ -105,7 +105,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         lenient().when(plainSchemaDAO.findById(anyString())).thenAnswer(ic -> {
             String schemaName = ic.getArgument(0);
             switch (schemaName) {
-                case "email", "firstname", "location", "index" -> {
+                case "email", "firstname", "location", "index", 
"user.valueWithDot" -> {
                     PlainSchema schema = mock(PlainSchema.class);
                     lenient().when(schema.getKey()).thenReturn(schemaName);
                     
lenient().when(schema.getType()).thenReturn(AttrSchemaType.String);
@@ -374,4 +374,13 @@ public class IntAttrNameParserTest extends AbstractTest {
             assertNotNull(e);
         }
     }
+
+    @Test 
+    public void issueSYNCOPE1894() throws ParseException {
+        IntAttrName intAttrName = intAttrNameParser.parse("user.valueWithDot", 
AnyTypeKind.USER);
+        assertNotNull(intAttrName);
+        assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
+        assertNull(intAttrName.getField());
+        assertEquals("user.valueWithDot", intAttrName.getSchema().getKey());
+    }
 }
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
index a005e94de1..d4ccd0f758 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
@@ -72,12 +72,14 @@ import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.Provision;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.to.PushTaskTO;
 import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.to.ReconStatus;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.SchemaTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
@@ -1849,4 +1851,49 @@ public class UserIssuesITCase extends AbstractITCase {
                         .toList().stream().anyMatch(pt -> 
ResourceOperation.DELETE == pt.
                         getOperation()));
     }
+
+    @Test
+    public void issueSYNCOPE1894() {
+        SchemaTO userWithDotSchema = new PlainSchemaTO();
+        userWithDotSchema.setKey("user.testWithDot");
+        userWithDotSchema.setAnyTypeClass("minimal user");
+        SCHEMA_SERVICE.create(SchemaType.PLAIN, userWithDotSchema);
+        
+        ResourceTO ldap = RESOURCE_SERVICE.read(RESOURCE_NAME_LDAP);
+        ldap.setKey("ldapWithDot");
+
+        Provision provision = 
ldap.getProvision(AnyTypeKind.USER.name()).orElseThrow();
+        provision.getMapping().getItems().removeIf(item -> 
"mail".equals(item.getIntAttrName()));
+        provision.getVirSchemas().clear();
+
+        ldap.getProvisions().clear();
+        ldap.getProvisions().add(provision);
+
+        Item item = new Item();
+        item.setIntAttrName(userWithDotSchema.getKey());
+        item.setExtAttrName("carLicense");
+        item.setPurpose(MappingPurpose.PROPAGATION);
+
+        provision.getMapping().add(item);
+
+        ldap = createResource(ldap);
+
+        try {
+            UserCR userCR = 
UserITCase.getUniqueSample("userwith...@syncope.apache.org");
+            userCR.getPlainAttrs().add(attr("user.testWithDot", 
"someCarLicenseValue"));
+            userCR.getResources().add(ldap.getKey());
+
+            ProvisioningResult<UserTO> result = createUser(userCR);
+            assertEquals(1, result.getPropagationStatuses().size());
+            
assertNotNull(result.getPropagationStatuses().get(0).getAfterObj());
+
+            Attr carLicense =
+                    
result.getPropagationStatuses().get(0).getAfterObj().getAttr("carLicense").orElseThrow();
+            assertEquals(1, carLicense.getValues().size());
+            assertEquals("someCarLicenseValue", carLicense.getValues().get(0));
+        } finally {
+            RESOURCE_SERVICE.delete(ldap.getKey());
+            SCHEMA_SERVICE.delete(SchemaType.PLAIN, 
userWithDotSchema.getKey());
+        }
+    }
 }

Reply via email to