You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2021/12/01 00:14:21 UTC

[sling-org-apache-sling-repoinit-parser] 01/01: SLING-10952 - Adding support for whitespace characters in group names

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

dklco pushed a commit to branch SLING-10952-whitespace-group-names
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-repoinit-parser.git

commit 1e8953e5d8f9d16cd10e5a7f9641fbac7a815e42
Author: Dan Klco <kl...@adobe.com>
AuthorDate: Tue Nov 30 19:14:10 2021 -0500

    SLING-10952 - Adding support for whitespace characters in group names
---
 .../repoinit/parser/impl/AuthorizableIdUtil.java   | 49 ++++++++++++++++++++++
 .../repoinit/parser/operations/AclGroupBase.java   |  6 ++-
 .../parser/operations/AddGroupMembers.java         |  4 +-
 .../repoinit/parser/operations/CreateGroup.java    |  3 +-
 .../repoinit/parser/operations/DeleteGroup.java    |  3 +-
 .../repoinit/parser/operations/Operation.java      |  4 ++
 .../parser/operations/RemoveGroupMembers.java      |  4 +-
 .../repoinit/parser/operations/SetAclPaths.java    |  1 +
 .../parser/operations/SetAclPrincipalBased.java    |  7 +++-
 .../parser/operations/SetAclPrincipals.java        | 10 +++--
 src/main/javacc/RepoInitGrammar.jjt                | 22 ++++++----
 src/test/resources/testcases/test-71-output.txt    | 20 +++++++++
 src/test/resources/testcases/test-71.txt           | 28 +++++++++++++
 13 files changed, 143 insertions(+), 18 deletions(-)

diff --git a/src/main/java/org/apache/sling/repoinit/parser/impl/AuthorizableIdUtil.java b/src/main/java/org/apache/sling/repoinit/parser/impl/AuthorizableIdUtil.java
new file mode 100644
index 0000000..09b958a
--- /dev/null
+++ b/src/main/java/org/apache/sling/repoinit/parser/impl/AuthorizableIdUtil.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.repoinit.parser.impl;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AuthorizableIdUtil {
+
+    private AuthorizableIdUtil() {
+        // hidden
+    }
+
+    /**
+     * Gets the authorizable ID handling cases where the value should be quoted
+     * (e.g. the authorizable id is not just an alphanumeric string)
+     * 
+     * @param authorizableId the authorizable ID to get
+     * @return the (potentially quoted) authorizable id
+     */
+    public static final String forRepoInitString(String authorizableId) {
+        return !authorizableId.matches(".*\\s.*") ? authorizableId : "\"" + authorizableId + "\"";
+    }
+
+    /**
+     * Gets the authorizable IDs handling cases where the value should be quoted
+     * (e.g. the authorizable id is not just an alphanumeric string)
+     * 
+     * @param authorizableIds the authorizable IDs to get
+     * @return the list of (potentially quoted) authorizable ids
+     */
+    public static final List<String> forRepoInitString(List<String> authorizableIds) {
+        return authorizableIds.stream().map(AuthorizableIdUtil::forRepoInitString).collect(Collectors.toList());
+    }
+}
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java b/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
index 12e02a3..bcd013a 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.Formatter;
 import java.util.List;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.apache.sling.repoinit.parser.operations.AclLine.Action;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
@@ -40,7 +41,7 @@ abstract class AclGroupBase extends Operation {
     private final List<String> aclOptions;
     
     protected AclGroupBase(List<AclLine> lines) {
-        this(lines,new ArrayList<String>());
+        this(lines,new ArrayList<>());
     }
     protected AclGroupBase(List<AclLine> lines, List<String> aclOptions) {
         this.lines = Collections.unmodifiableList(lines);
@@ -74,7 +75,8 @@ abstract class AclGroupBase extends Operation {
                     String pathStr = pathsToString(line.getProperty(AclLine.PROP_PATHS));
                     onOrFor = (pathStr.isEmpty()) ? "" : " on " + pathStr;
                 } else {
-                    onOrFor = " for " + listToString(line.getProperty(AclLine.PROP_PRINCIPALS));
+                    onOrFor = " for " + listToString(
+                            AuthorizableIdUtil.forRepoInitString(line.getProperty(AclLine.PROP_PRINCIPALS)));
                 }
                 formatter.format("    %s %s%s%s%s%n", action, privileges, onOrFor,
                         nodetypesToString(line.getProperty(AclLine.PROP_NODETYPES)),
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java b/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
index 5ccb49f..7572aef 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
@@ -19,6 +19,7 @@ package org.apache.sling.repoinit.parser.operations;
 
 import java.util.List;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -55,7 +56,8 @@ public class AddGroupMembers extends Operation {
     @NotNull
     @Override
     public String asRepoInitString() {
-        return String.format("add %s to group %s%n", listToString(members), groupname);
+        return String.format("add %s to group %s%n", listToString(AuthorizableIdUtil.forRepoInitString(members)),
+                AuthorizableIdUtil.forRepoInitString(groupname));
     }
 
     public String getGroupname() {
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
index 3384c46..40db1e7 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
@@ -17,6 +17,7 @@
 
 package org.apache.sling.repoinit.parser.operations;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.apache.sling.repoinit.parser.impl.WithPathOptions;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
@@ -63,7 +64,7 @@ public class CreateGroup extends OperationWithPathOptions {
     @NotNull
     @Override
     public String asRepoInitString() {
-        return asRepoInitString("group", groupname);
+        return asRepoInitString("group", AuthorizableIdUtil.forRepoInitString(groupname));
     }
 
     public String getGroupname() {
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
index 1fcb807..fba5ab0 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
@@ -17,6 +17,7 @@
 
 package org.apache.sling.repoinit.parser.operations;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -46,7 +47,7 @@ public class DeleteGroup extends Operation {
     @NotNull
     @Override
     public String asRepoInitString() {
-        return String.format("delete group %s%n", groupname);
+        return String.format("delete group %s", AuthorizableIdUtil.forRepoInitString(groupname));
     }
 
     public String getGroupname() {
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java b/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
index e1b1d80..37f2c30 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
@@ -17,6 +17,7 @@
 
 package org.apache.sling.repoinit.parser.operations;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -72,6 +73,9 @@ public abstract class Operation {
                     if (s.startsWith(":") && s.contains("#")) {
                         String func = s.substring(1, s.indexOf(":",1));
                         String s2 = s.substring(func.length()+2, s.lastIndexOf('#'));
+                        if ("authorizable".equals(func)) {
+                            s2 = AuthorizableIdUtil.forRepoInitString(s2);
+                        }
                         String trailingPath = (s.endsWith("#")) ?  "" : s.substring(s.indexOf("#")+1);
                         return func + "(" + s2 +")" + trailingPath;
                     } else {
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java b/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
index 320e647..a72b482 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
@@ -19,6 +19,7 @@ package org.apache.sling.repoinit.parser.operations;
 
 import java.util.List;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -55,7 +56,8 @@ public class RemoveGroupMembers extends Operation {
     @NotNull
     @Override
     public String asRepoInitString() {
-        return String.format("remove %s from group %s%n", listToString(members), groupname);
+        return String.format("remove %s from group %s%n", listToString(AuthorizableIdUtil.forRepoInitString(members)),
+                AuthorizableIdUtil.forRepoInitString(groupname));
     }
 
     public String getGroupname() {
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
index e43aed7..9195039 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
@@ -41,6 +41,7 @@ public class SetAclPaths extends AclGroupBase {
         this.paths = Collections.unmodifiableList(paths);
     }
     
+    @Override
     protected String getParametersDescription() {
         final StringBuilder sb = new StringBuilder();
         sb.append(paths);
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
index c8d8538..5d83b99 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -33,7 +34,7 @@ public class SetAclPrincipalBased extends AclGroupBase {
     private final List<String> principals;
 
     public SetAclPrincipalBased(List<String> principals, List<AclLine> lines) {
-        this(principals,lines,new ArrayList<String>());
+        this(principals,lines,new ArrayList<>());
     }
 
     public SetAclPrincipalBased(List<String> principals, List<AclLine> lines, List<String> aclOptions) {
@@ -41,6 +42,7 @@ public class SetAclPrincipalBased extends AclGroupBase {
         this.principals = Collections.unmodifiableList(principals);
     }
 
+    @Override
     protected String getParametersDescription() {
         final StringBuilder sb = new StringBuilder();
         sb.append(principals);
@@ -51,7 +53,8 @@ public class SetAclPrincipalBased extends AclGroupBase {
     @NotNull
     @Override
     public String asRepoInitString() {
-        String topline = String.format("set principal ACL for %s%s%n", listToString(principals), getAclOptionsString());
+        String topline = String.format("set principal ACL for %s%s%n",
+                listToString(AuthorizableIdUtil.forRepoInitString(principals)), getAclOptionsString());
         return asRepoInit(topline, true);
     }
 
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
index 2c8c1b1..4556a8a 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.sling.repoinit.parser.impl.AuthorizableIdUtil;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
@@ -33,7 +34,7 @@ public class SetAclPrincipals extends AclGroupBase {
     private final List<String> principals;
     
     public SetAclPrincipals(List<String> principals, List<AclLine> lines) {
-        this(principals,lines,new ArrayList<String>());
+        this(principals,lines,new ArrayList<>());
     }
 
     public SetAclPrincipals(List<String> principals,List<AclLine> lines, List<String> aclOptions) {
@@ -41,6 +42,7 @@ public class SetAclPrincipals extends AclGroupBase {
         this.principals = Collections.unmodifiableList(principals);
     }
 
+    @Override
     protected String getParametersDescription() {
         final StringBuilder sb = new StringBuilder();
         sb.append(principals);
@@ -55,10 +57,12 @@ public class SetAclPrincipals extends AclGroupBase {
             List<String> paths = line.getProperty(AclLine.PROP_PATHS);
             return paths == null || paths.isEmpty();
         })) {
-            String topline = String.format("set repository ACL for %s%s%n", listToString(principals), getAclOptionsString());
+            String topline = String.format("set repository ACL for %s%s%n",
+                    listToString(AuthorizableIdUtil.forRepoInitString(principals)), getAclOptionsString());
             return asRepoInit(topline, true);
         } else {
-            String topline = String.format("set ACL for %s%s%n", listToString(principals), getAclOptionsString());
+            String topline = String.format("set ACL for %s%s%n",
+                    listToString(AuthorizableIdUtil.forRepoInitString(principals)), getAclOptionsString());
             return asRepoInit(topline, true);
         }
     }
diff --git a/src/main/javacc/RepoInitGrammar.jjt b/src/main/javacc/RepoInitGrammar.jjt
index 1e4236d..d8f93cd 100644
--- a/src/main/javacc/RepoInitGrammar.jjt
+++ b/src/main/javacc/RepoInitGrammar.jjt
@@ -178,8 +178,8 @@ List<String> principalsList() :
     List<String> principals = new ArrayList<String>(); 
 }
 {
-    t = <STRING> { principals.add(t.image); } 
-    ( <COMMA> t = <STRING> { principals.add(t.image); } )* 
+    t = authorizableId() { principals.add(t.image); } 
+    ( <COMMA> t = authorizableId() { principals.add(t.image); } )* 
     { return principals; }
 }
 
@@ -247,7 +247,7 @@ String usernameList() :
     Token t = null;
 }
 {
-    ( t = <STRING> ) { names.add(t.image); }
+    ( t = authorizableId() ) { names.add(t.image); }
     // disable lists for now, not supported downstream
     // ( <COMMA> t = <STRING> { names.add(t.image); }) *
 
@@ -654,7 +654,7 @@ void createGroupStatement(List<Operation> result) :
 }
 {
     <CREATE> <GROUP> 
-    ( group = <STRING> )
+    ( group = authorizableId() )
     ( wpopt = withPathStatement() ) ?
 
     {
@@ -668,7 +668,7 @@ void deleteGroupStatement(List<Operation> result) :
 }
 {
     <DELETE> <GROUP> 
-    ( group = <STRING> )
+    ( group = authorizableId() )
 
     {
         result.add(new DeleteGroup(group.image));
@@ -754,7 +754,7 @@ void addToGroupStatement(List<Operation> result) :
     <ADD>
     members =  principalsList()
     <TO> <GROUP>
-    group = <STRING>
+    group = authorizableId()
 
     {
         result.add(new AddGroupMembers(members, group.image));
@@ -771,13 +771,21 @@ void removeFromGroupStatement(List<Operation> result) :
     <REMOVE>
     members =  principalsList()
     <FROM> <GROUP>
-    group = <STRING>
+    group = authorizableId()
 
     {
         result.add(new RemoveGroupMembers(members, group.image));
     }
 }
 
+Token authorizableId() :
+{
+    Token t = null;
+}
+{
+    (t = <STRING> | t = quotedString() ) { return t; }
+}
+
 Token propertyValue() :
 {
     Token t = null;
diff --git a/src/test/resources/testcases/test-71-output.txt b/src/test/resources/testcases/test-71-output.txt
new file mode 100644
index 0000000..daabab9
--- /dev/null
+++ b/src/test/resources/testcases/test-71-output.txt
@@ -0,0 +1,20 @@
+CreateGroup Test Group
+CreateGroup Test Group With Spaces with path /thePathF
+DeleteGroup Test Group
+SetAclPaths on /content 
+  AclLine ALLOW {principals=[Test Group, user1], privileges=[jcr:read]}
+SetAclPaths on /content 
+  AclLine ALLOW {principals=[Test Group- Cool People, Test Group, user1], privileges=[jcr:read]}
+SetAclPrincipals for user1 Test Group u2 
+  AclLine ALLOW {paths=[/content], privileges=[jcr:read]}
+SetAclPrincipalBased for user1 Test Group ACLOptions=[mergePreserve]
+  AclLine REMOVE_ALL {paths=[/libs, /apps]}
+  AclLine ALLOW {paths=[/content], privileges=[jcr:read]}
+SetAclPaths on /test ACLOptions=[merge]
+  AclLine REMOVE_ALL {principals=[user1, Test Group, user2]}
+SetProperties on :authorizable:bob# :authorizable:Test Group#
+  PropertyLine stringProp{String}=[{String}hello, you again!]
+SetProperties on :authorizable:bob#/nested :authorizable:Test Group#/nested
+  PropertyLine stringProp{String}=[{String}hello, you nested again!]
+AddGroupMembers user1 Test Group 2000 user2 in group Parent Group
+RemoveGroupMembers user1 Test Group 2000 user2 in group Parent Group
\ No newline at end of file
diff --git a/src/test/resources/testcases/test-71.txt b/src/test/resources/testcases/test-71.txt
new file mode 100644
index 0000000..0114a21
--- /dev/null
+++ b/src/test/resources/testcases/test-71.txt
@@ -0,0 +1,28 @@
+# Support quoted Group IDs
+create group "Test Group"
+create group "Test Group With Spaces" with path /thePathF
+delete group "Test Group"
+set ACL on /content
+    allow jcr:read for "Test Group",user1
+end
+set ACL on /content
+    allow jcr:read for "Test Group- Cool People","Test Group",user1
+end
+set ACL for user1,"Test Group",u2
+    allow jcr:read on /content
+end
+set principal ACL for user1,"Test Group" (ACLOptions=mergePreserve)
+    remove * on /libs,/apps
+    allow jcr:read on /content
+end
+set ACL on /test (ACLOptions=merge)
+    remove * for user1,"Test Group",user2
+end
+set properties on authorizable(bob), authorizable("Test Group")
+  set stringProp to "hello, you again!"
+end
+set properties on authorizable(bob)/nested, authorizable("Test Group")/nested
+  set stringProp to "hello, you nested again!"
+end
+add user1,"Test Group 2000",user2 to group "Parent Group"
+remove user1,"Test Group 2000",user2 from group "Parent Group"
\ No newline at end of file