/* * 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.jackrabbit.core.security.authorization.acl; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; import org.apache.jackrabbit.core.security.authorization.AbstractEvaluationTest; import org.apache.jackrabbit.core.security.authorization.AccessControlConstants; import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry; import org.apache.jackrabbit.test.NotExecutableException; import javax.jcr.AccessDeniedException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.security.AccessControlList; import javax.jcr.security.AccessControlManager; import javax.jcr.security.AccessControlPolicy; import javax.jcr.security.AccessControlPolicyIterator; import javax.jcr.security.Privilege; import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * <code>ACWriteTest</code>... */ public class AcReadWriteTest extends AbstractEvaluationTest { protected String path; protected String childNPath; protected String childNPath2; protected String childPPath; protected String childchildPPath; protected String siblingPath; @Override protected void setUp() throws Exception { super.setUp(); // create some nodes below the test root in order to apply ac-stuff Node node = testRootNode.addNode(nodeName1, testNodeType); Node cn1 = node.addNode(nodeName2, testNodeType); Property cp1 = node.setProperty(propertyName1, "anyValue"); Node cn2 = node.addNode(nodeName3, testNodeType); Property ccp1 = cn1.setProperty(propertyName1, "childNodeProperty"); Node n2 = testRootNode.addNode(nodeName2, testNodeType); superuser.save(); path = node.getPath(); childNPath = cn1.getPath(); childNPath2 = cn2.getPath(); childPPath = cp1.getPath(); childchildPPath = ccp1.getPath(); siblingPath = n2.getPath(); } @Override protected boolean isExecutable() { return EvaluationUtil.isExecutable(acMgr); } @Override protected JackrabbitAccessControlList getPolicy(AccessControlManager acM, String path, Principal principal) throws RepositoryException, AccessDeniedException, NotExecutableException { return EvaluationUtil.getPolicy(acM, path, principal); } @Override protected Map<String, Value> getRestrictions(Session s, String path) { return Collections.emptyMap(); } public void testAccessControlPrivileges() throws RepositoryException, NotExecutableException { /* precondition: testuser must have READ-only permission on test-node and below */ checkReadOnly(path); /* grant 'testUser' rep:write, rep:readAccessControl and rep:modifyAccessControl privileges at 'path' */ Privilege[] privileges = privilegesFromNames(new String[] { PrivilegeRegistry.REP_WRITE, Privilege.JCR_READ_ACCESS_CONTROL, Privilege.JCR_MODIFY_ACCESS_CONTROL }); JackrabbitAccessControlList tmpl = givePrivileges(path, privileges, getRestrictions(superuser, path)); Session testSession = getTestSession(); AccessControlManager testAcMgr = getTestACManager(); /* testuser must have - permission to view AC items - permission to modify AC items */ // the policy node however must be visible to the test-user assertTrue(testSession.itemExists(tmpl.getPath() + "/rep:policy")); testAcMgr.getPolicies(tmpl.getPath()); testAcMgr.removePolicy(tmpl.getPath(), tmpl); } /** * Test if a new applicable policy can be applied within a individual * subtree where AC-modification is allowed. * * @throws RepositoryException * @throws NotExecutableException * @see <a href="https://issues.apache.org/jira/browse/JCR-2869">JCR-2869</a> */ public void testSetNewPolicy() throws RepositoryException, NotExecutableException { /* precondition: testuser must have READ-only permission on test-node and below */ checkReadOnly(path); /* grant 'testUser' rep:write, rep:readAccessControl and rep:modifyAccessControl privileges at 'path' */ Privilege[] privileges = privilegesFromNames(new String[] { PrivilegeRegistry.REP_WRITE, Privilege.JCR_READ_ACCESS_CONTROL, Privilege.JCR_MODIFY_ACCESS_CONTROL }); JackrabbitAccessControlList tmpl = givePrivileges(path, privileges, getRestrictions(superuser, path)); AccessControlManager testAcMgr = getTestACManager(); /* testuser must be allowed to set a new policy at a child node. */ AccessControlPolicyIterator it = testAcMgr.getApplicablePolicies(childNPath); while (it.hasNext()) { AccessControlPolicy plc = it.nextAccessControlPolicy(); testAcMgr.setPolicy(childNPath, plc); testAcMgr.removePolicy(childNPath, plc); } } public void testSetModifiedPolicy() throws RepositoryException, NotExecutableException { /* precondition: testuser must have READ-only permission on test-node and below */ checkReadOnly(path); /* grant 'testUser' rep:write, rep:readAccessControl and rep:modifyAccessControl privileges at 'path' */ Privilege[] privileges = privilegesFromNames(new String[] { PrivilegeRegistry.REP_WRITE, Privilege.JCR_READ_ACCESS_CONTROL, Privilege.JCR_MODIFY_ACCESS_CONTROL }); JackrabbitAccessControlList tmpl = givePrivileges(path, privileges, getRestrictions(superuser, path)); /* testuser must be allowed to set (modified) policy at target node. */ Session testSession = getTestSession(); AccessControlManager testAcMgr = getTestACManager(); AccessControlPolicy[] policies = testAcMgr.getPolicies(path); assertEquals(1, policies.length); assertTrue(policies[0] instanceof AccessControlList); AccessControlList acl = (AccessControlList) policies[0]; if (acl.addAccessControlEntry(testUser.getPrincipal(), new Privilege[] {testAcMgr.privilegeFromName(Privilege.JCR_LOCK_MANAGEMENT)})) { testAcMgr.setPolicy(path, acl); testSession.save(); } } public void testRetrievePrivilegesOnAcNodes() throws NotExecutableException, RepositoryException { /* precondition: testuser must have READ-only permission on test-node and below */ checkReadOnly(path); // give 'testUser' jcr:readAccessControl privileges at 'path' Privilege[] privileges = privilegesFromNames(new String[] { Privilege.JCR_READ_ACCESS_CONTROL }); JackrabbitAccessControlList tmpl = givePrivileges(path, privileges, getRestrictions(superuser, path)); /* testuser must be allowed to read ac-content at target node. */ Session testSession = getTestSession(); AccessControlManager testAcMgr = getTestACManager(); assertTrue(testAcMgr.hasPrivileges(path, privileges)); AccessControlPolicy[] policies = testAcMgr.getPolicies(path); assertEquals(1, policies.length); assertTrue(policies[0] instanceof JackrabbitAccessControlList); String aclNodePath = null; Node n = superuser.getNode(path); for (NodeIterator itr = n.getNodes(); itr.hasNext();) { Node child = itr.nextNode(); if (child.isNodeType("rep:Policy")) { aclNodePath = child.getPath(); } } if (aclNodePath == null) { fail("Expected node at " + path + " to have an ACL child node."); } assertTrue(testAcMgr.hasPrivileges(aclNodePath, privileges)); assertTrue(testSession.hasPermission(aclNodePath, Session.ACTION_READ)); for (NodeIterator aceNodes = superuser.getNode(aclNodePath).getNodes(); aceNodes.hasNext();) { String aceNodePath = aceNodes.nextNode().getPath(); assertTrue(testAcMgr.hasPrivileges(aceNodePath, privileges)); assertTrue(testSession.hasPermission(aceNodePath, Session.ACTION_READ)); } } public void testReadAccessControl() throws NotExecutableException, RepositoryException { /* precondition: testuser must have READ-only permission on test-node and below */ checkReadOnly(path); /* give 'testUser' jcr:readAccessControl privileges at subtree below path excluding the node at path itself. */ Privilege[] privileges = privilegesFromNames(new String[] { Privilege.JCR_READ_ACCESS_CONTROL }); Map<String, Value> restrictions = new HashMap<String, Value>(getRestrictions(superuser, path)); restrictions.put(AccessControlConstants.P_GLOB.toString(), vf.createValue("/" + nodeName2)); JackrabbitAccessControlList tmpl = givePrivileges(path, privileges, restrictions); /* testuser must not be allowed to read AC content at the target node; however, retrieving potential AC content at 'childPath' is granted. */ Session testSession = getTestSession(); AccessControlManager testAcMgr = getTestACManager(); assertFalse(testAcMgr.hasPrivileges(path, privileges)); try { testAcMgr.getPolicies(path); fail("AccessDeniedException expected"); } catch (AccessDeniedException e) { // success. } assertTrue(testAcMgr.hasPrivileges(childNPath, privileges)); assertEquals(0, testAcMgr.getPolicies(childNPath).length); /* similarly reading the corresponding AC items at 'path' must be forbidden */ String aclNodePath = null; Node n = superuser.getNode(path); for (NodeIterator itr = n.getNodes(); itr.hasNext();) { Node child = itr.nextNode(); if (child.isNodeType("rep:Policy")) { aclNodePath = child.getPath(); } } if (aclNodePath == null) { fail("Expected node at " + path + " to have an ACL child node."); } assertFalse(testSession.nodeExists(aclNodePath)); for (NodeIterator aceNodes = superuser.getNode(aclNodePath).getNodes(); aceNodes.hasNext();) { Node aceNode = aceNodes.nextNode(); String aceNodePath = aceNode.getPath(); assertFalse(testSession.nodeExists(aceNodePath)); for (PropertyIterator it = aceNode.getProperties(); it.hasNext();) { assertFalse(testSession.propertyExists(it.nextProperty().getPath())); } } } }