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:20 UTC

[sling-org-apache-sling-repoinit-parser] branch SLING-10952-whitespace-group-names created (now 1e8953e)

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

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


      at 1e8953e  SLING-10952 - Adding support for whitespace characters in group names

This branch includes the following new commits:

     new 1e8953e  SLING-10952 - Adding support for whitespace characters in group names

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


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

Posted by dk...@apache.org.
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