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