You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by tm...@apache.org on 2017/09/19 09:01:32 UTC

svn commit: r1808845 - in /sling/trunk/bundles: extensions/repoinit/parser/src/main/javacc/ jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/ jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/

Author: tmaret
Date: Tue Sep 19 09:01:32 2017
New Revision: 1808845

URL: http://svn.apache.org/viewvc?rev=1808845&view=rev
Log:
SLING-7061 - Access control setup of repository-level permissions (i.e. null path)

* Add parser and JCR implementation

Modified:
    sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt
    sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java
    sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
    sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java

Modified: sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt?rev=1808845&r1=1808844&r2=1808845&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt (original)
+++ sling/trunk/bundles/extensions/repoinit/parser/src/main/javacc/RepoInitGrammar.jjt Tue Sep 19 09:01:32 2017
@@ -68,6 +68,7 @@ TOKEN:
 |   < MIXIN: "mixin" >
 |   < PATH: "path" >
 |   < END: "end" >
+|   < REPOSITORY: "repository" >
 |   < USER: "user" >
 |   < NODETYPES: "nodetypes" >
 |   < REGISTER: "register" >
@@ -127,6 +128,7 @@ List<Operation> parse() :
         serviceUserStatement(result) 
         | setAclPaths(result) 
         | setAclPrincipals(result)
+        | setAclRepository(result)
         | createPathStatement(result)
         | registerNamespaceStatement(result)
         | registerNodetypesStatement(result)
@@ -400,6 +402,38 @@ List<String> aclOptions() :
     }
 }
 
+void setAclRepository(List<Operation> result) :
+{
+    List<AclLine> lines = new ArrayList<AclLine>();
+    List<String> principals;
+    List<String> privileges;
+    List<String> aclOptions;
+    AclLine line = null;
+
+}
+{
+    <SET> <REPOSITORY> <ACL> <FOR> principals = principalsList() aclOptions=aclOptions() <EOL>
+    (
+        ( <REMOVE> <STAR> )
+            {
+                line = new AclLine(AclLine.Action.REMOVE_ALL);
+                lines.add(line);
+            }
+        | ( line = privilegesLineOperation() privileges = namespacedItemsList() )
+            {
+                line.setProperty(AclLine.PROP_PRIVILEGES, privileges);
+                lines.add(line);
+            }
+        | ( blankLine() )
+    )+
+    <END>
+    ( <EOL> | <EOF> )
+
+    {
+        result.add(new SetAclPrincipals(principals, lines, aclOptions));
+    }
+}
+
 void setAclPrincipals(List<Operation> result) :
 {
     List <String> principals;

Modified: sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java?rev=1808845&r1=1808844&r2=1808845&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java (original)
+++ sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclUtil.java Tue Sep 19 09:01:32 2017
@@ -100,52 +100,60 @@ public class AclUtil {
 
     public static void setAcl(Session session, List<String> principals, List<String> paths, List<String> privileges, boolean isAllow, List<RestrictionClause> restrictionClauses)
             throws RepositoryException {
-
-        final String [] privArray = privileges.toArray(new String[privileges.size()]);
-        final Privilege[] jcrPriv = AccessControlUtils.privilegesFromNames(session, privArray);
-
-        for(String path : paths) {
+        for (String path : paths) {
             if(!session.nodeExists(path)) {
                 throw new PathNotFoundException("Cannot set ACL on non-existent path " + path);
             }
+            setAcl(session, principals, path, privileges, isAllow, restrictionClauses);
+        }
+    }
+
+    private static void setAcl(Session session, List<String> principals, String path, List<String> privileges, boolean isAllow, List<RestrictionClause> restrictionClauses)
+            throws RepositoryException {
+
+        final String [] privArray = privileges.toArray(new String[privileges.size()]);
+        final Privilege[] jcrPriv = AccessControlUtils.privilegesFromNames(session, privArray);
 
-            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(session, path);
+        JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(session, path);
 
-            LocalRestrictions localRestrictions = createLocalRestrictions(restrictionClauses, acl, session);
+        LocalRestrictions localRestrictions = createLocalRestrictions(restrictionClauses, acl, session);
 
-            AccessControlEntry[] existingAces = acl.getAccessControlEntries();
+        AccessControlEntry[] existingAces = acl.getAccessControlEntries();
 
-            boolean changed = false;
-            for (String name : principals) {
-                final Principal principal;
-                if (EveryonePrincipal.NAME.equals(name)) {
-                    principal = AccessControlUtils.getPrincipal(session, name);
-                } else {
-                    final Authorizable authorizable = UserUtil.getAuthorizable(session, name);
-                    if (authorizable == null) {
-                        throw new IllegalStateException("Authorizable not found:" + name);
-                    }
-                    principal = authorizable.getPrincipal();
-                }
-                if (principal == null) {
-                    throw new IllegalStateException("Principal not found: " + name);
+        boolean changed = false;
+        for (String name : principals) {
+            final Principal principal;
+            if (EveryonePrincipal.NAME.equals(name)) {
+                principal = AccessControlUtils.getPrincipal(session, name);
+            } else {
+                final Authorizable authorizable = UserUtil.getAuthorizable(session, name);
+                if (authorizable == null) {
+                    throw new IllegalStateException("Authorizable not found:" + name);
                 }
-                LocalAccessControlEntry newAce = new LocalAccessControlEntry(principal, jcrPriv, isAllow, localRestrictions);
-                if (contains(existingAces, newAce)) {
-                    LOG.info("Not adding {} to path {} since an equivalent access control entry already exists", newAce, path);
-                    continue;
-                }
-                acl.addEntry(newAce.principal, newAce.privileges, newAce.isAllow,
-                        newAce.restrictions.getRestrictions(), newAce.restrictions.getMVRestrictions());
-                changed = true;
+                principal = authorizable.getPrincipal();
             }
-            if ( changed ) {
-                getJACM(session).setPolicy(path, acl);
+            if (principal == null) {
+                throw new IllegalStateException("Principal not found: " + name);
             }
-
+            LocalAccessControlEntry newAce = new LocalAccessControlEntry(principal, jcrPriv, isAllow, localRestrictions);
+            if (contains(existingAces, newAce)) {
+                LOG.info("Not adding {} to path {} since an equivalent access control entry already exists", newAce, path);
+                continue;
+            }
+            acl.addEntry(newAce.principal, newAce.privileges, newAce.isAllow,
+                    newAce.restrictions.getRestrictions(), newAce.restrictions.getMVRestrictions());
+            changed = true;
+        }
+        if ( changed ) {
+            getJACM(session).setPolicy(path, acl);
         }
     }
 
+    public static void setRepositoryAcl(Session session, List<String> principals, List<String> privileges, boolean isAllow, List<RestrictionClause> restrictionClauses)
+           throws RepositoryException {
+        setAcl(session, principals, (String)null, privileges, isAllow, restrictionClauses);
+    }
+
     // visible for testing
     static boolean contains(AccessControlEntry[] existingAces, LocalAccessControlEntry newAce) throws RepositoryException {
         for (int i = 0 ; i < existingAces.length; i++) {

Modified: sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java?rev=1808845&r1=1808844&r2=1808845&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java (original)
+++ sling/trunk/bundles/jcr/repoinit/src/main/java/org/apache/sling/jcr/repoinit/impl/AclVisitor.java Tue Sep 19 09:01:32 2017
@@ -64,12 +64,28 @@ class AclVisitor extends DoNothingVisito
         }
     }
 
+    private void setRepositoryAcl(AclLine line, Session s, List<String> principals, List<String> privileges, boolean isAllow) {
+        try {
+            log.info("Adding repository level ACL '{}' entry '{}' for {}", isAllow ? "allow" : "deny", privileges, principals);
+            List<RestrictionClause> restrictions = line.getRestrictions();
+            AclUtil.setRepositoryAcl(s, principals, privileges, isAllow, restrictions);
+        } catch(Exception e) {
+            throw new RuntimeException("Failed to set repository level ACL (" + e.toString() + ") " + line, e);
+        }
+    }
+
     @Override
     public void visitSetAclPrincipal(SetAclPrincipals s) {
         final List<String> principals = s.getPrincipals();
         for(AclLine line : s.getLines()) {
             final boolean isAllow = line.getAction().equals(AclLine.Action.ALLOW);
-            setAcl(line, session, principals, require(line, PROP_PATHS), require(line, PROP_PRIVILEGES), isAllow);
+            final List<String> paths = line.getProperty(PROP_PATHS);
+            if (paths != null && ! paths.isEmpty()) {
+                setAcl(line, session, principals, paths, require(line, PROP_PRIVILEGES), isAllow);
+            } else {
+                setRepositoryAcl(line, session, principals, require(line, PROP_PRIVILEGES), isAllow);
+            }
+
         }
      }
 

Modified: sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java?rev=1808845&r1=1808844&r2=1808845&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java (original)
+++ sling/trunk/bundles/jcr/repoinit/src/test/java/org/apache/sling/jcr/repoinit/GeneralAclTest.java Tue Sep 19 09:01:32 2017
@@ -25,6 +25,8 @@ import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
 
 import org.apache.sling.jcr.repoinit.impl.TestUtil;
 import org.apache.sling.repoinit.parser.RepoInitParsingException;
@@ -146,6 +148,100 @@ public class GeneralAclTest {
         }
     }
 
+    @Test
+    public void addRepositoryAcl() throws Exception {
+        final String aclSetup =
+                "set repository ACL for " + userA + "," + userB + "\n"
+                + "allow jcr:namespaceManagement\n"
+                + "allow jcr:nodeTypeDefinitionManagement\n"
+                + "end"
+                ;
+
+        U.parseAndExecute(aclSetup);
+        verifyRegisterNamespace(userA, "a", "http://a", true);
+        verifyRegisterNamespace(userB, "b", "http://b", true);
+        verifyRegisterNamespace(U.username, "c", "http://c", false);
+        verifyRegisterNodeType(userA, "typeA", true);
+        verifyRegisterNodeType(userB, "typeB", true);
+        verifyRegisterNodeType(U.username, "typeC", false);
+    }
+
+    @Test
+    public void addRepositoryAclInMultipleBlocks() throws Exception {
+        final String aclSetup =
+                  "set repository ACL for " + userA + "\n"
+                +    "allow jcr:namespaceManagement,jcr:nodeTypeDefinitionManagement\n"
+                + "end\n"
+                + "set repository ACL for " + userB + "\n"
+                +    "allow jcr:namespaceManagement\n"
+                + "end"
+                ;
+
+        U.parseAndExecute(aclSetup);
+        verifyRegisterNamespace(userA, "a", "http://a", true);
+        verifyRegisterNamespace(userB, "b", "http://b", true);
+        verifyRegisterNodeType(userA, "typeA", true);
+        verifyRegisterNodeType(userB, "typeB", false);
+    }
+
+    @Test
+    public void addRepositoryAclInSequence() throws Exception {
+        final String aclSetup =
+                  "set repository ACL for " + U.username + "\n"
+                +    "deny jcr:namespaceManagement,jcr:nodeTypeDefinitionManagement\n"
+                +    "allow jcr:namespaceManagement,jcr:nodeTypeDefinitionManagement\n"
+                + "end\n"
+                + "set repository ACL for " + U.username + "\n"
+                +    "deny jcr:namespaceManagement\n"
+                + "end"
+                ;
+
+        U.parseAndExecute(aclSetup);
+        verifyRegisterNodeType(U.username, "typeC", true);
+        verifyRegisterNamespace(U.username, "c", "http://c", false);
+    }
+
+    /**
+     * Verify the success/failure when registering a node type.
+     * Registering a node type requires to be granted the jcr:nodeTypeDefinitionManagement privilege.
+     */
+    private void verifyRegisterNodeType(String username, String typeName, boolean successExpected) {
+        Session userSession = null;
+        try {
+            userSession = U.loginService(username);
+            NodeTypeManager nodeTypeManager = userSession.getWorkspace().getNodeTypeManager();
+            NodeTypeTemplate type = nodeTypeManager.createNodeTypeTemplate();
+            type.setName(typeName);
+            nodeTypeManager.registerNodeType(type, true);
+            assertTrue("Register node type succeeded " + typeName, successExpected);
+        } catch (RepositoryException e) {
+            assertTrue("Error registering node type " + typeName + " " + e.getMessage(), !successExpected);
+        } finally {
+            if (userSession != null) {
+                userSession.logout();
+            }
+        }
+    }
+
+
+    /**
+     * Verify the success/failure when registering a namespace.
+     * Registering a namespace successfully requires to be granted the jcr:namespaceManagement privilege.
+     */
+    private void verifyRegisterNamespace(String username, String prefix, String uri, boolean successExpected) {
+        Session userSession = null;
+        try {
+            userSession = U.loginService(username);
+            userSession.getWorkspace().getNamespaceRegistry().registerNamespace(prefix, uri);
+            assertTrue("Register namespace succeeded " + prefix + uri, successExpected);
+        } catch (RepositoryException e) {
+            assertTrue("Error registering namespace " + prefix + uri + " " + e.getMessage(), !successExpected);
+        } finally {
+            if (userSession != null) {
+                userSession.logout();
+            }
+        }
+    }
 
     /**
      * Verifies success/failure of adding a child