You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2008/08/27 17:12:07 UTC
svn commit: r689499 [6/11] - in /jackrabbit/trunk:
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/retention/
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/sec...
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java?rev=689499&r1=689498&r2=689499&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedEditor.java Wed Aug 27 08:12:04 2008
@@ -17,363 +17,117 @@
package org.apache.jackrabbit.core.security.authorization.combined;
import org.apache.jackrabbit.api.jsr283.security.AccessControlException;
-import org.apache.jackrabbit.api.jsr283.security.Privilege;
-import org.apache.jackrabbit.api.security.principal.PrincipalManager;
-import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
-import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
-import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
-import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
-import org.apache.jackrabbit.core.security.authorization.acl.ACLEditor;
-import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
-import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
-import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.Path;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFactory;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
+import java.util.Arrays;
/**
* <code>CombinedEditor</code>...
*/
-class CombinedEditor extends ACLEditor {
+class CombinedEditor implements AccessControlEditor {
private static Logger log = LoggerFactory.getLogger(CombinedEditor.class);
- private final NamePathResolver systemResolver;
- private final String acRootPath;
+ private final AccessControlEditor[] editors;
- CombinedEditor(SessionImpl session, NamePathResolver systemResolver,
- Path acRootPath) throws RepositoryException {
- super(session);
- this.systemResolver = systemResolver;
- this.acRootPath = session.getJCRPath(acRootPath);
- }
-
- PolicyTemplate getPolicyTemplate(Principal principal) throws RepositoryException {
- if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
- throw new AccessControlException("Unknown principal.");
- }
-
- String nPath = getPathToAcNode(principal);
- if (session.nodeExists(nPath)) {
- return getPolicyTemplate(nPath);
- } else {
- // no policy for the given principal
- log.debug("No combined policy template for Principal " + principal.getName());
- return null;
- }
+ CombinedEditor(AccessControlEditor[] editors) {
+ this.editors = editors;
}
//------------------------------------------------< AccessControlEditor >---
/**
- * @see AccessControlEditor#getPolicyTemplate(String)
- */
- public PolicyTemplate getPolicyTemplate(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
- checkProtectsNode(nodePath);
-
- NodeImpl acNode = getAcNode(nodePath);
- if (acNode != null) {
- return createTemplate(acNode);
- } else {
- // nodeID not below rep:accesscontrol -> delegate to ACLEditor
- return super.getPolicyTemplate(nodePath);
- }
- }
-
- /**
- * @see AccessControlEditor#editPolicyTemplate(String)
+ * @see AccessControlEditor#getPolicies(String)
*/
- public PolicyTemplate editPolicyTemplate(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
- checkProtectsNode(nodePath);
-
- if (Text.isDescendant(acRootPath, nodePath)) {
- NodeImpl acNode = getAcNode(nodePath);
- if (acNode == null) {
- // check validity and create the ac node
- getPrincipal(nodePath);
- acNode = createAcNode(nodePath);
+ public AccessControlPolicy[] getPolicies(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
+ List templates = new ArrayList(editors.length);
+ for (int i = 0; i < editors.length; i++) {
+ AccessControlPolicy[] ts = editors[i].getPolicies(nodePath);
+ if (ts.length > 0) {
+ templates.addAll(Arrays.asList(ts));
}
- return createTemplate(acNode);
- } else {
- // nodeID not below rep:accesscontrol -> delegate to ACLEditor
- return super.editPolicyTemplate(nodePath);
}
+ return (AccessControlPolicy[]) templates.toArray(new AccessControlPolicy[templates.size()]);
}
/**
- * @see AccessControlEditor#editPolicyTemplate(Principal)
+ * @see AccessControlEditor#editAccessControlPolicies(String)
*/
- public PolicyTemplate editPolicyTemplate(Principal principal) throws RepositoryException {
- if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
- throw new AccessControlException("Unknown principal.");
- }
- String nPath = getPathToAcNode(principal);
- if (!session.nodeExists(nPath)) {
- createAcNode(nPath);
- }
- return getPolicyTemplate(nPath);
- }
-
- /**
- * @see AccessControlEditor#setPolicyTemplate(String,PolicyTemplate)
- */
- public void setPolicyTemplate(String nodePath, PolicyTemplate template) throws AccessControlException, PathNotFoundException, RepositoryException {
- checkProtectsNode(nodePath);
-
- if (template instanceof PolicyTemplateImpl) {
- PolicyTemplateImpl at = (PolicyTemplateImpl) template;
- if (!nodePath.equals(at.getPath())) {
- throw new AccessControlException("Attempt to store PolicyTemplate to a wrong node.");
- }
- NodeImpl acNode = getAcNode(nodePath);
- if (acNode == null) {
- throw new PathNotFoundException("No such node " + nodePath);
+ public AccessControlPolicy[] editAccessControlPolicies(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
+ List templates = new ArrayList(editors.length);
+ for (int i = 0; i < editors.length; i++) {
+ try {
+ templates.addAll(Arrays.asList(editors[i].editAccessControlPolicies(nodePath)));
+ } catch (AccessControlException e) {
+ log.debug(e.getMessage());
+ // ignore.
}
-
- /*
- in order to assert that the parent (ac-controlled node) gets
- modified an existing ACL node is removed first and the recreated.
- this also asserts that all ACEs are cleared without having to
- access and removed the explicitely
- */
- NodeImpl aclNode;
- if (acNode.hasNode(N_POLICY)) {
- aclNode = acNode.getNode(N_POLICY);
- removeSecurityItem(aclNode);
- }
- /* now (re) create it */
- aclNode = addSecurityNode(acNode, N_POLICY, NT_REP_ACL);
-
- /* add all entries defined on the template */
- PolicyEntry[] aces = (PolicyEntry[]) template.getEntries();
- for (int i = 0; i < aces.length; i++) {
- PolicyEntryImpl ace = (PolicyEntryImpl) aces[i];
-
- // create the ACE node
- Name nodeName = getUniqueNodeName(aclNode, "entry");
- Name ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
- NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
-
- ValueFactory vf = session.getValueFactory();
- // write the rep:principalName property
- setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(ace.getPrincipal().getName()));
- // ... and the rep:privileges property
- Privilege[] privs = ace.getPrivileges();
- Value[] vs = new Value[privs.length];
- for (int j = 0; j < privs.length; j++) {
- vs[j] = vf.createValue(privs[j].getName());
- }
- setSecurityProperty(aceNode, P_PRIVILEGES, vs);
-
- // remove local namespace remapping from the node path before
- // storing the path value.
- String pathValue = systemResolver.getJCRPath(session.getQPath(ace.getNodePath()));
- setSecurityProperty(aceNode, P_NODE_PATH, vf.createValue(pathValue, PropertyType.PATH));
-
- // TODO: TOBEFIXED respect namespace sensitive parts of the glob
- setSecurityProperty(aceNode, P_GLOB, vf.createValue(ace.getGlob()));
- }
- } else {
- // try super class
- super.setPolicyTemplate(nodePath, template);
}
+ return (AccessControlPolicy[]) templates.toArray(new AccessControlPolicy[templates.size()]);
}
/**
- * @see AccessControlEditor#removePolicyTemplate(String)
- * @param nodePath
+ * @see AccessControlEditor#editAccessControlPolicies(Principal)
*/
- public PolicyTemplate removePolicyTemplate(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
- checkProtectsNode(nodePath);
-
- NodeImpl acNode = getAcNode(nodePath);
- if (acNode != null) {
- if (isAccessControlled(acNode)) {
- // build the template in order to have a return value
- PolicyTemplate tmpl = createTemplate(acNode);
- removeSecurityItem(acNode.getNode(N_POLICY));
- return tmpl;
- } else {
- log.debug("No policy present to remove at " + nodePath);
- return null;
+ public AccessControlPolicy[] editAccessControlPolicies(Principal principal) throws RepositoryException {
+ List templates = new ArrayList();
+ for (int i = 0; i < editors.length; i++) {
+ try {
+ templates.addAll(Arrays.asList(editors[i].editAccessControlPolicies(principal)));
+ } catch (AccessControlException e) {
+ log.debug(e.getMessage());
+ // ignore.
}
- } else {
- // nodeID not below rep:accesscontrol -> delegate to ACLEditor
- return super.removePolicyTemplate(nodePath);
}
+ return (AccessControlPolicy[]) templates.toArray(new AccessControlPolicy[templates.size()]);
}
- //------------------------------------------------------------< private >---
/**
- *
- * @param nodePath
- * @return
- * @throws PathNotFoundException
- * @throws RepositoryException
+ * @see AccessControlEditor#setPolicy(String,AccessControlPolicy)
*/
- private NodeImpl getAcNode(String nodePath) throws PathNotFoundException, RepositoryException {
- if (Text.isDescendant(acRootPath, nodePath)) {
- return (NodeImpl) session.getNode(nodePath);
- } else {
- // node outside of rep:accesscontrol tree -> not handled by this editor.
- return null;
- }
- }
-
- private NodeImpl createAcNode(String acPath) throws RepositoryException {
- String[] segms = Text.explode(acPath, '/', false);
- NodeImpl node = (NodeImpl) session.getRootNode();
- for (int i = 0; i < segms.length; i++) {
- Name nName = session.getQName(segms[i]);
- if (node.hasNode(nName)) {
- node = node.getNode(nName);
- if (!node.isNodeType(NT_REP_ACCESS_CONTROL)) {
- // should never get here.
- throw new RepositoryException("Internal error: Unexpected nodetype " + node.getPrimaryNodeType().getName() + " below /rep:accessControl");
- }
- } else {
- node = addSecurityNode(node, nName, NT_REP_ACCESS_CONTROL);
+ public void setPolicy(String nodePath, AccessControlPolicy template) throws AccessControlException, PathNotFoundException, RepositoryException {
+ for (int i = 0; i < editors.length; i++) {
+ try {
+ // return as soon as the first editor successfully handled the
+ // specified template
+ editors[i].setPolicy(nodePath, template);
+ log.debug("Set template " + template + " using " + editors[i]);
+ return;
+ } catch (AccessControlException e) {
+ log.debug(e.getMessage());
+ // ignore and try next
}
}
- return node;
- }
- /**
- * Test if the Node identified by <code>id</code> is itself part of ACL
- * defining content. It this case setting or modifying an AC-policy is
- * obviously not possible.
- *
- * @param nodePath
- * @throws AccessControlException If the given id identifies a Node that
- * represents a ACL or ACE item.
- * @throws RepositoryException
- */
- private void checkProtectsNode(String nodePath) throws RepositoryException {
- if (session.nodeExists(nodePath)) {
- NodeImpl n = (NodeImpl) session.getNode(nodePath);
- if (n.isNodeType(NT_REP_ACL) || n.isNodeType(NT_REP_ACE)) {
- throw new AccessControlException("Node " + nodePath + " defines ACL or ACE.");
- }
- }
- }
-
- /**
- *
- * @param principal
- * @return
- * @throws RepositoryException
- */
- private String getPathToAcNode(Principal principal) throws RepositoryException {
- StringBuffer princPath = new StringBuffer(acRootPath);
- if (principal instanceof ItemBasedPrincipal) {
- princPath.append(((ItemBasedPrincipal) principal).getPath());
- } else {
- princPath.append("/");
- princPath.append(Text.escapeIllegalJcrChars(principal.getName()));
- }
- return princPath.toString();
- }
-
- private Principal getPrincipal(String pathToACNode) throws RepositoryException {
- String name = Text.unescapeIllegalJcrChars(Text.getName(pathToACNode));
- PrincipalManager pMgr = session.getPrincipalManager();
- if (!pMgr.hasPrincipal(name)) {
- throw new AccessControlException("Unknown principal.");
- }
- return pMgr.getPrincipal(name);
- }
-
- /**
- *
- * @param node
- * @return
- * @throws RepositoryException
- */
- private boolean isAccessControlled(NodeImpl node) throws RepositoryException {
- return node.isNodeType(NT_REP_ACCESS_CONTROL) && node.hasNode(N_POLICY);
+ // none accepted -> throw
+ throw new AccessControlException("None of the editors accepted policy " + template + " at " + nodePath);
}
/**
- *
- * @param acNode
- * @return
- * @throws RepositoryException
+ * @see AccessControlEditor#removePolicy(String,AccessControlPolicy)
*/
- private PolicyTemplate createTemplate(NodeImpl acNode) throws RepositoryException {
- if (!acNode.isNodeType(NT_REP_ACCESS_CONTROL)) {
- throw new RepositoryException("Expected node of type rep:AccessControl.");
- }
-
- Principal principal;
- String principalName = Text.unescapeIllegalJcrChars(acNode.getName());
- PrincipalManager pMgr = ((SessionImpl) acNode.getSession()).getPrincipalManager();
- if (pMgr.hasPrincipal(principalName)) {
- principal = pMgr.getPrincipal(principalName);
- } else {
- log.warn("Principal with name " + principalName + " unknown to PrincipalManager.");
- // TODO: rather throw?
- principal = new PrincipalImpl(principalName);
- }
-
- // build the list of policy entries;
- List entries = new ArrayList();
- if (acNode.hasNode(N_POLICY)) {
- NodeImpl aclNode = acNode.getNode(N_POLICY);
- // loop over all entries in the aclNode for the princ-Principal
- // and compare if they apply to the Node with 'nodeId'
- for (NodeIterator aceNodes = aclNode.getNodes(); aceNodes.hasNext();) {
- NodeImpl aceNode = (NodeImpl) aceNodes.nextNode();
- PolicyEntryImpl ace = createEntry(aceNode, principal);
- if (ace != null) {
- entries.add(ace);
- }
+ public void removePolicy(String nodePath,
+ AccessControlPolicy policy) throws AccessControlException, PathNotFoundException, RepositoryException {
+ for (int i = 0; i < editors.length; i++) {
+ try {
+ // return as soon as the first editor successfully handled the
+ // specified template
+ editors[i].removePolicy(nodePath, policy);
+ log.debug("Removed template " + policy + " using " + editors[i]);
+ return;
+ } catch (AccessControlException e) {
+ log.debug(e.getMessage());
+ // ignore and try next
}
}
- return new PolicyTemplateImpl(entries, principal, acNode.getPath());
- }
-
- /**
- *
- * @param node
- * @param principal
- * @return
- * @throws RepositoryException
- */
- private PolicyEntryImpl createEntry(NodeImpl node, Principal principal) throws RepositoryException {
- if (!node.isNodeType(AccessControlConstants.NT_REP_ACE)) {
- log.warn("Unexpected nodetype. Was not rep:ACE.");
- return null;
- }
-
- boolean allow = node.isNodeType(NT_REP_GRANT_ACE);
-
- Value[] pValues = node.getProperty(P_PRIVILEGES).getValues();
- String[] pNames = new String[pValues.length];
- for (int i = 0; i < pValues.length; i++) {
- pNames[i] = pValues[i].getString();
- }
- int privileges = PrivilegeRegistry.getBits(pNames);
-
- String pV = node.getProperty(P_NODE_PATH).getString();
- String nodePath = session.getJCRPath(systemResolver.getQPath(pV));
-
- // TODO: make sure local namespace remappings are respected.
- String glob = node.getProperty(P_GLOB).getString();
-
- return new PolicyEntryImpl(principal, privileges, allow, nodePath, glob);
+ // neither of the editors was able to remove a policy at nodePath
+ throw new AccessControlException("Unable to remove template " + policy);
}
}
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java?rev=689499&r1=689498&r2=689499&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java Wed Aug 27 08:12:04 2008
@@ -16,71 +16,60 @@
*/
package org.apache.jackrabbit.core.security.authorization.combined;
-import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
-import org.apache.jackrabbit.api.security.principal.PrincipalManager;
-import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.observation.SynchronousEventListener;
-import org.apache.jackrabbit.core.security.SecurityConstants;
import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
-import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
-import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.security.authorization.PolicyEntry;
-import org.apache.jackrabbit.core.security.authorization.PolicyTemplate;
-import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
-import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
+import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.principalbased.ACLProvider;
+import org.apache.jackrabbit.core.ItemImpl;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
-import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.jcr.Item;
-import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-import java.security.Principal;
+import javax.jcr.ItemNotFoundException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Iterator;
/**
* <code>CombinedProvider</code>...
*/
-public class CombinedProvider extends AbstractAccessControlProvider implements AccessControlConstants {
+public class CombinedProvider extends AbstractAccessControlProvider {
private static Logger log = LoggerFactory.getLogger(CombinedProvider.class);
- // TODO: add means to show effective-policy to a user.
- // TODO: TOBEFIXED proper evaluation of permissions respecting resource-based ACLs.
- // TODO: TOBEFIXED assert proper evaluation order of group/non-group principal-ACLs
+ private AccessControlProvider[] providers;
- private CombinedEditor editor;
- private NodeImpl acRoot;
-
- public CombinedProvider() {
- super("Combined AC policy", "Policy evaluating user-based and resource-based ACLs.");
+ //-------------------------------------------------< AccessControlUtils >---
+ /**
+ * @see AccessControlUtils#isAcItem(Path)
+ */
+ public boolean isAcItem(Path absPath) throws RepositoryException {
+ for (int i = 0; i < providers.length; i++) {
+ if (providers[i] instanceof AccessControlUtils && ((AccessControlUtils) providers[i]).isAcItem(absPath)) {
+ return true;
+ }
+ }
+ return false;
}
- //--------------------------------------< AbstractAccessControlProvider >---
/**
- * @see AbstractAccessControlProvider#isAcItem(Path)
+ * @see AccessControlUtils#isAcItem(ItemImpl)
*/
- protected boolean isAcItem(Path absPath) throws RepositoryException {
- Path.Element[] elems = absPath.getElements();
- for (int i = 0; i < elems.length; i++) {
- if (N_POLICY.equals(elems[i].getName())) {
+ public boolean isAcItem(ItemImpl item) throws RepositoryException {
+ for (int i = 0; i < providers.length; i++) {
+ if (providers[i] instanceof AccessControlUtils && ((AccessControlUtils) providers[i]).isAcItem(item)) {
return true;
}
}
@@ -89,65 +78,50 @@
//----------------------------------------------< AccessControlProvider >---
/**
- * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
+ * @see AccessControlProvider#close()
*/
- public void init(Session systemSession, Map options) throws RepositoryException {
- super.init(systemSession, options);
-
- NodeImpl root = (NodeImpl) session.getRootNode();
- if (root.hasNode(N_ACCESSCONTROL)) {
- acRoot = root.getNode(N_ACCESSCONTROL);
- if (!acRoot.isNodeType(NT_REP_ACCESS_CONTROL)) {
- throw new RepositoryException("Error while initializing Access Control Provider: Found ac-root to be wrong node type " + acRoot.getPrimaryNodeType().getName());
- }
- } else {
- acRoot = root.addNode(N_ACCESSCONTROL, NT_REP_ACCESS_CONTROL, null);
+ public void close() {
+ for (int i = 0; i < providers.length; i++) {
+ providers[i].close();
}
+ super.close();
+ }
- editor = new CombinedEditor(session, resolver, resolver.getQPath(acRoot.getPath()));
- try {
- log.info("Install initial ACL:...");
-
- PrincipalManager pMgr = session.getPrincipalManager();
- log.info("... Privilege.ALL for administrators.");
- Principal administrators;
- String pName = SecurityConstants.ADMINISTRATORS_NAME;
- if (pMgr.hasPrincipal(pName)) {
- administrators = pMgr.getPrincipal(pName);
- } else {
- log.warn("Administrators principal group is missing.");
- administrators = new PrincipalImpl(pName);
- }
+ /**
+ * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
+ */
+ public void init(Session systemSession, Map configuration) throws RepositoryException {
+ super.init(systemSession, configuration);
- String glob = GlobPattern.WILDCARD_ALL;
- PolicyTemplate pt = editor.editPolicyTemplate(administrators);
- pt.setEntry(new PolicyEntryImpl(administrators, PrivilegeRegistry.ALL, true, root.getPath(), glob));
- editor.setPolicyTemplate(pt.getPath(), pt);
-
- Principal everyone = pMgr.getEveryone();
- log.info("... Privilege.READ for everyone.");
- pt = editor.editPolicyTemplate(everyone);
- pt.setEntry(new PolicyEntryImpl(everyone, PrivilegeRegistry.READ, true, root.getPath(), glob));
- editor.setPolicyTemplate(pt.getPath(), pt);
-
- session.save();
- log.info("... done.");
-
- } catch (RepositoryException e) {
- log.error("Failed to set-up minimal access control for root node of workspace " + session.getWorkspace().getName());
- session.getRootNode().refresh(false);
- throw e;
- }
+ // this provider combines the result of 2 (currently hardcoded) AC-providers
+ // TODO: make this configurable
+ providers = new AccessControlProvider[2];
+
+ // 1) a resource-based ACL provider, that is not inited with default
+ // permissions and should only be used to overrule the permissions
+ // granted or denied by the default provider (see 2).
+ providers[0] = new org.apache.jackrabbit.core.security.authorization.acl.ACLProvider();
+ Map config = new HashMap(configuration);
+ config.put(PARAM_OMIT_DEFAULT_PERMISSIONS, Boolean.TRUE);
+ providers[0].init(systemSession, config);
+
+ // 2) the principal-base ACL provider which is intended to provide
+ // the default/standard permissions present at an item for a given
+ // set of principals.
+ providers[1] = new ACLProvider();
+ providers[1].init(systemSession, configuration);
}
/**
- * @see AccessControlProvider#getAccessControlEntries(Path)
- * @param absPath
- */
- public AccessControlEntry[] getAccessControlEntries(Path absPath) throws RepositoryException {
- checkInitialized();
- // TODO: TOBEFIXED
- return new AccessControlEntry[0];
+ * @see AccessControlProvider#getEffectivePolicies(Path)
+ */
+ public AccessControlPolicy[] getEffectivePolicies(Path absPath)
+ throws ItemNotFoundException, RepositoryException {
+ List l = new ArrayList();
+ for (int i = 0; i < providers.length; i++) {
+ l.addAll(Arrays.asList(providers[i].getEffectivePolicies(absPath)));
+ }
+ return (AccessControlPolicy[]) l.toArray(new AccessControlPolicy[l.size()]);
}
/**
@@ -155,18 +129,21 @@
*/
public AccessControlEditor getEditor(Session editingSession) {
checkInitialized();
- if (editingSession instanceof SessionImpl) {
+ List editors = new ArrayList();
+ for (int i = 0; i < providers.length; i++) {
try {
- return new CombinedEditor((SessionImpl) editingSession,
- session, session.getQPath(acRoot.getPath()));
+ editors.add(providers[i].getEditor(editingSession));
} catch (RepositoryException e) {
- // should never get here
- log.error("Internal error:", e.getMessage());
+ log.debug(e.getMessage());
+ // ignore.
}
}
-
- log.debug("Unable to build access control editor " + CombinedEditor.class.getName() + ".");
- return null;
+ if (!editors.isEmpty()) {
+ return new CombinedEditor((AccessControlEditor[]) editors.toArray(new AccessControlEditor[editors.size()]));
+ } else {
+ log.debug("None of the derived access control providers supports editing.");
+ return null;
+ }
}
/**
@@ -176,8 +153,6 @@
checkInitialized();
if (isAdminOrSystem(principals)) {
return getAdminPermissions();
- } else if (isReadOnly(principals)) {
- return getReadOnlyPermissions();
} else {
return new CompiledPermissionImpl(principals);
}
@@ -191,7 +166,13 @@
if (isAdminOrSystem(principals)) {
return true;
} else {
- return new CompiledPermissionImpl(principals, false).grants(PathFactoryImpl.getInstance().getRootPath(), Permission.READ);
+ CompiledPermissions cp = new CompiledPermissionImpl(principals);
+ try {
+ Path rootPath = PathFactoryImpl.getInstance().getRootPath();
+ return cp.grants(rootPath, Permission.READ);
+ } finally {
+ cp.close();
+ }
}
}
@@ -199,39 +180,24 @@
/**
*
*/
- private class CompiledPermissionImpl extends AbstractCompiledPermissions
- implements SynchronousEventListener {
+ private class CompiledPermissionImpl extends AbstractCompiledPermissions {
- private final Set principals;
- private final Set acPaths;
- private Entries entries;
+ private final List cPermissions;
/**
* @param principals
- * @throws RepositoryException
*/
- private CompiledPermissionImpl(Set principals) throws RepositoryException {
- this(principals, true);
- }
-
- /**
- * @param principals
- * @throws RepositoryException
- */
- private CompiledPermissionImpl(Set principals, boolean listenToEvents) throws RepositoryException {
-
- this.principals = principals;
- acPaths = new HashSet(principals.size());
- entries = reload();
-
- // TODO: describe
- if (listenToEvents) {
- int events = Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED |
- Event.PROPERTY_REMOVED | Event.NODE_ADDED | Event.NODE_REMOVED;
- String[] ntNames = new String[] {
- session.getJCRName(NT_REP_ACE)
- };
- observationMgr.addEventListener(this, events, acRoot.getPath(), true, null, ntNames, false);
+ private CompiledPermissionImpl(Set principals) throws
+ RepositoryException {
+ this.cPermissions = new ArrayList();
+ for (int i = 0; i < providers.length; i++) {
+ CompiledPermissions cp = providers[i].compilePermissions(principals);
+ if (cp instanceof AbstractCompiledPermissions) {
+ cPermissions.add(cp);
+ } else {
+ // TODO: deal with other impls.
+ log.warn("AbstractCompiledPermissions expected. Found " + cp.getClass().getName() + " -> ignore.");
+ }
}
}
@@ -239,214 +205,36 @@
/**
* @see AbstractCompiledPermissions#buildResult(Path)
*/
- protected synchronized Result buildResult(Path absPath) throws RepositoryException {
- if (!absPath.isAbsolute()) {
- throw new RepositoryException("Absolute path expected.");
- }
-
- /* Test if the given path points to a Node (or an existing or non
- * existing direct decendant of an existing Node) that stores
- * AC-information
- */
- boolean isAclItem = isAcItem(absPath);
- String jcrPath = session.getJCRPath(absPath);
- int permissions;
- if (session.itemExists(jcrPath)) {
- permissions = entries.getPermissions(session.getItem(jcrPath), isAclItem);
- } else {
- Node parent = null;
- String parentPath = jcrPath;
- while (parent == null) {
- parentPath = Text.getRelativeParent(parentPath, 1);
- if (parentPath.length() == 0) {
- // root node reached
- parent = session.getRootNode();
- } else if (session.nodeExists(parentPath)) {
- parent = session.getNode(parentPath);
- }
- }
- String relPath = jcrPath.substring(parent.getPath().length() + 1);
- permissions = entries.getPermissions(parent, relPath, isAclItem);
- }
- /* TODO: privileges can only be determined for nodes. */
- int privileges = entries.getPrivileges(jcrPath);
- return new Result(permissions, privileges);
- }
-
- //--------------------------------------------< CompiledPermissions >---
- /**
- * @see CompiledPermissions#close()
- */
- public void close() {
- try {
- observationMgr.removeEventListener(this);
- } catch (RepositoryException e) {
- log.debug("Unable to unregister listener: ", e.getMessage());
- }
- super.close();
- }
-
- //--------------------------------------------------< EventListener >---
- /**
- * @see EventListener#onEvent(EventIterator)
- */
- public synchronized void onEvent(EventIterator events) {
- try {
- boolean reload = false;
- while (events.hasNext() && !reload) {
- Event ev = events.nextEvent();
- String path = ev.getPath();
- // only invalidate cache if any of the events affects the
- // nodes defining permissions for the principals.
- switch (ev.getType()) {
- case Event.NODE_ADDED:
- case Event.NODE_REMOVED:
- reload = acPaths.contains(Text.getRelativeParent(path, 2));
- break;
- case Event.PROPERTY_ADDED:
- case Event.PROPERTY_CHANGED:
- case Event.PROPERTY_REMOVED:
- reload = acPaths.contains(Text.getRelativeParent(path, 3));
- break;
- default:
- // illegal event-type: should never occur. ignore
- reload = false;
- break;
- }
- }
- // eventually reload the ACL and clear the cache
- if (reload) {
- clearCache();
- // reload the acl
- entries = reload();
- }
- } catch (RepositoryException e) {
- // should never get here
- log.warn("Internal error: ", e.getMessage());
- }
- }
-
- /**
- *
- * @return
- * @throws RepositoryException
- */
- private Entries reload() throws RepositoryException {
- // reload the paths
- acPaths.clear();
-
- // acNodes must be ordered in the same order as the principals
- // in order to obtain proper acl-evalution in case the given
- // principal-set is ordered.
- List allACEs = new ArrayList();
- // build acl-hierarchy assuming that principal-order determines the
- // acl-inheritance.
- for (Iterator it = principals.iterator(); it.hasNext();) {
- Principal princ = (Principal) it.next();
- PolicyTemplate at = editor.getPolicyTemplate(princ);
- if (at == null || at.isEmpty()) {
- log.debug("No matching ACL node found for principal " + princ.getName() + " -> principal ignored.");
- } else {
- // retrieve the ACEs from the node
- PolicyEntry[] aces = (PolicyEntry[]) at.getEntries();
- allACEs.addAll(Arrays.asList(aces));
- acPaths.add(at.getPath());
- }
+ protected Result buildResult(Path absPath) throws RepositoryException {
+ Result res = null;
+ for (Iterator it = cPermissions.iterator(); it.hasNext();) {
+ AbstractCompiledPermissions acp = (AbstractCompiledPermissions) it.next();
+ Result other = acp.getResult(absPath);
+ res = (res == null) ? other : res.combine(other);
}
- return new Entries(allACEs);
- }
- }
-
- //--------------------------------------------------------------------------
-
- private static class Entries {
-
- private final List entries;
-
- private Entries(List entries) {
- this.entries = entries;
+ return res;
}
/**
- * Loop over all entries and evaluate allows/denies for those matching
- * the given jcrPath.
- *
- * @param target Existing target item for which the permissions will be
- * evaluated.
- * @param protectsACL
- * @return
- * @throws RepositoryException
+ * @see AbstractCompiledPermissions#getResult(Path)
*/
- private int getPermissions(Item target, boolean protectsACL) throws RepositoryException {
- int allows = 0;
- int denies = 0;
- for (Iterator it = entries.iterator(); it.hasNext() && allows != Permission.ALL;) {
- PolicyEntryImpl entr = (PolicyEntryImpl) it.next();
- if (entr.matches(target)) {
- int privs = entr.getPrivilegeBits();
- int permissions = Permission.calculatePermissions(privs, privs, protectsACL);
- if (entr.isAllow()) {
- allows |= Permission.diff(permissions, denies);
- } else {
- denies |= Permission.diff(permissions, allows);
- }
- }
- }
- return allows;
+ public Result getResult(Path absPath) throws RepositoryException {
+ // TODO: missing caching
+ return buildResult(absPath);
}
+ //--------------------------------------------< CompiledPermissions >---
/**
- * loop over all entries and evaluate allows/denies for those matching
- * the given jcrPath.
- *
- * @param parent Existing parent of the target to be evaluated.
- * @param relPath relative path to a non-existing child item to calculate the
- * permissions for.
- * @param protectsACL
- * @return
- * @throws RepositoryException
+ * @see CompiledPermissions#close()
*/
- private int getPermissions(Node parent, String relPath, boolean protectsACL) throws RepositoryException {
- int allows = 0;
- int denies = 0;
- String jcrPath = parent.getPath() + "/" + relPath;
-
- for (Iterator it = entries.iterator(); it.hasNext() && allows != Permission.ALL;) {
- PolicyEntryImpl entr = (PolicyEntryImpl) it.next();
- if (entr.matches(jcrPath)) {
- int privs = entr.getPrivilegeBits();
- int permissions = Permission.calculatePermissions(privs, privs, protectsACL);
- if (entr.isAllow()) {
- allows |= Permission.diff(permissions, denies);
- } else {
- denies |= Permission.diff(permissions, allows);
- }
- }
+ public synchronized void close() {
+ // close all c-permissions retained in the list and clear the list.
+ for (Iterator it = cPermissions.iterator(); it.hasNext();) {
+ CompiledPermissions cp = (CompiledPermissions) it.next();
+ cp.close();
+ it.remove();
}
- return allows;
- }
-
- private int getPrivileges(String nodePath) throws RepositoryException {
- // TODO: improve. avoid duplicate evaluation ...
- int allows = 0;
- int denies = 0;
- for (Iterator it = entries.iterator(); it.hasNext() && allows != Permission.ALL;) {
- PolicyEntryImpl entr = (PolicyEntryImpl) it.next();
- // loop over all entries and evaluate allows/denies for those
- // matching the given jcrPath
- // TODO: check again which ACEs must be respected.
- // TODO: maybe ancestor-defs only if glob = *?
- String np = entr.getNodePath();
- // TODO: TOBEFIXED Text.isDescendant that returns false if np==root-path
- if (np.equals(nodePath) || "/".equals(np) || Text.isDescendant(np, nodePath)) {
- if (entr.isAllow()) {
- allows |= PrivilegeRegistry.diff(entr.getPrivilegeBits(), denies);
- } else {
- denies |= PrivilegeRegistry.diff(entr.getPrivilegeBits(), allows);
- }
- }
- }
- return allows;
+ super.close();
}
}
}
\ No newline at end of file
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java?rev=689499&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java Wed Aug 27 08:12:04 2008
@@ -0,0 +1,369 @@
+/*
+ * $Id$
+ *
+ * Copyright 1997-2005 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+package org.apache.jackrabbit.core.security.authorization.principalbased;
+
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlException;
+import org.apache.jackrabbit.api.jsr283.security.Privilege;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SecurityItemModifier;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
+import org.apache.jackrabbit.core.security.authorization.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.conversion.NameParser;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import java.security.Principal;
+
+/**
+ * <code>CombinedEditor</code>...
+ */
+public class ACLEditor extends SecurityItemModifier implements AccessControlEditor, AccessControlConstants {
+
+ private static Logger log = LoggerFactory.getLogger(ACLEditor.class);
+ /**
+ * Default name for ace nodes
+ */
+ private static final String DEFAULT_ACE_NAME = "ace";
+
+ /**
+ * the editing session
+ */
+ private final SessionImpl session;
+ private final String acRootPath;
+
+ ACLEditor(SessionImpl session, Path acRootPath) throws RepositoryException {
+ this.session = session;
+ this.acRootPath = session.getJCRPath(acRootPath);
+ }
+
+ ACLTemplate getACL(Principal principal) throws RepositoryException {
+ if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
+ throw new AccessControlException("Unknown principal.");
+ }
+ String nPath = getPathToAcNode(principal);
+ if (session.nodeExists(nPath)) {
+ return (ACLTemplate) getPolicies(nPath)[0];
+ } else {
+ // no policy for the given principal
+ log.debug("No combined policy template for Principal " + principal.getName());
+ return null;
+ }
+ }
+
+ //------------------------------------------------< AccessControlEditor >---
+ /**
+ * @see AccessControlEditor#getPolicies(String)
+ */
+ public AccessControlPolicy[] getPolicies(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
+ checkProtectsNode(nodePath);
+
+ NodeImpl acNode = getAcNode(nodePath);
+ if (acNode != null) {
+ return new AccessControlPolicy[] {createTemplate(acNode)};
+ } else {
+ return new AccessControlPolicy[0];
+ }
+ }
+
+ /**
+ * @see AccessControlEditor#editAccessControlPolicies(String)
+ */
+ public AccessControlPolicy[] editAccessControlPolicies(String nodePath) throws AccessControlException, PathNotFoundException, RepositoryException {
+ checkProtectsNode(nodePath);
+
+ if (Text.isDescendant(acRootPath, nodePath)) {
+ NodeImpl acNode = getAcNode(nodePath);
+ if (acNode == null) {
+ // check validity and create the ac node
+ getPrincipal(nodePath);
+ acNode = createAcNode(nodePath);
+ }
+ return new AccessControlPolicy[] {createTemplate(acNode)};
+ } else {
+ // nodePath not below rep:accesscontrol -> not editable
+ return new AccessControlPolicy[0];
+ }
+ }
+
+ /**
+ * @see AccessControlEditor#editAccessControlPolicies(Principal)
+ */
+ public AccessControlPolicy[] editAccessControlPolicies(Principal principal) throws RepositoryException {
+ if (!session.getPrincipalManager().hasPrincipal(principal.getName())) {
+ throw new AccessControlException("Unknown principal.");
+ }
+ String nPath = getPathToAcNode(principal);
+ if (!session.nodeExists(nPath)) {
+ createAcNode(nPath);
+ }
+ return getPolicies(nPath);
+ }
+
+ /**
+ * @see AccessControlEditor#setPolicy(String,AccessControlPolicy)
+ */
+ public void setPolicy(String nodePath, AccessControlPolicy policy) throws AccessControlException, PathNotFoundException, RepositoryException {
+ checkProtectsNode(nodePath);
+ checkValidPolicy(nodePath, policy);
+
+ ACLTemplate acl = (ACLTemplate) policy;
+ NodeImpl acNode = getAcNode(nodePath);
+ if (acNode == null) {
+ throw new PathNotFoundException("No such node " + nodePath);
+ }
+ // write the entries to the node
+ /*
+ in order to assert that the parent (ac-controlled node) gets
+ modified an existing ACL node is removed first and the recreated.
+ this also asserts that all ACEs are cleared without having to
+ access and removed the explicitely
+ */
+ NodeImpl aclNode;
+ if (acNode.hasNode(N_POLICY)) {
+ aclNode = acNode.getNode(N_POLICY);
+ removeSecurityItem(aclNode);
+ }
+ /* now (re) create it */
+ aclNode = addSecurityNode(acNode, N_POLICY, NT_REP_ACL);
+
+ /* add all entries defined on the template */
+ AccessControlEntry[] aces = acl.getAccessControlEntries();
+ for (int i = 0; i < aces.length; i++) {
+ JackrabbitAccessControlEntry ace = (JackrabbitAccessControlEntry) aces[i];
+
+ // create the ACE node
+ Name nodeName = getUniqueNodeName(aclNode, "entry");
+ Name ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
+ NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
+
+ ValueFactory vf = session.getValueFactory();
+ // write the rep:principalName property
+ setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(ace.getPrincipal().getName()));
+ // ... and the rep:privileges property
+ Privilege[] privs = ace.getPrivileges();
+ Value[] vs = new Value[privs.length];
+ for (int j = 0; j < privs.length; j++) {
+ vs[j] = vf.createValue(privs[j].getName());
+ }
+ setSecurityProperty(aceNode, P_PRIVILEGES, vs);
+
+ // store the restrictions:
+ String[] restrNames = ace.getRestrictionNames();
+ for (int rnIndex = 0; rnIndex < restrNames.length; rnIndex++) {
+ Name pName = session.getQName(restrNames[rnIndex]);
+ Value value = ace.getRestriction(restrNames[rnIndex]);
+ setSecurityProperty(aceNode, pName, value);
+ }
+ }
+ }
+
+ /**
+ * @see AccessControlEditor#removePolicy(String,AccessControlPolicy)
+ */
+ public void removePolicy(String nodePath, AccessControlPolicy policy) throws AccessControlException, PathNotFoundException, RepositoryException {
+ checkProtectsNode(nodePath);
+ checkValidPolicy(nodePath, policy);
+
+ NodeImpl acNode = getAcNode(nodePath);
+ if (acNode != null) {
+ if (isAccessControlled(acNode)) {
+ // build the template in order to have a return value
+ AccessControlPolicy tmpl = createTemplate(acNode);
+ if (tmpl.equals(policy)) {
+ removeSecurityItem(acNode.getNode(N_POLICY));
+ return;
+ }
+ }
+ }
+ // node either not access-controlled or the passed policy didn't apply
+ // to the node at 'nodePath' -> throw exception.no policy was removed
+ throw new AccessControlException("Policy " + policy + " does not apply to " + nodePath);
+ }
+
+ //------------------------------------------------------------< private >---
+ /**
+ *
+ * @param nodePath
+ * @return
+ * @throws PathNotFoundException
+ * @throws RepositoryException
+ */
+ private NodeImpl getAcNode(String nodePath) throws PathNotFoundException, RepositoryException {
+ if (Text.isDescendant(acRootPath, nodePath)) {
+ return (NodeImpl) session.getNode(nodePath);
+ } else {
+ // node outside of rep:accesscontrol tree -> not handled by this editor.
+ return null;
+ }
+ }
+
+ private NodeImpl createAcNode(String acPath) throws RepositoryException {
+ String[] segms = Text.explode(acPath, '/', false);
+ NodeImpl node = (NodeImpl) session.getRootNode();
+ for (int i = 0; i < segms.length; i++) {
+ Name nName = session.getQName(segms[i]);
+ if (node.hasNode(nName)) {
+ node = node.getNode(nName);
+ if (!node.isNodeType(NT_REP_ACCESS_CONTROL)) {
+ // should never get here.
+ throw new RepositoryException("Internal error: Unexpected nodetype " + node.getPrimaryNodeType().getName() + " below /rep:accessControl");
+ }
+ } else {
+ node = addSecurityNode(node, nName, NT_REP_ACCESS_CONTROL);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Check if the Node identified by <code>id</code> is itself part of ACL
+ * defining content. It this case setting or modifying an AC-policy is
+ * obviously not possible.
+ *
+ * @param nodePath
+ * @throws AccessControlException If the given id identifies a Node that
+ * represents a ACL or ACE item.
+ * @throws RepositoryException
+ */
+ private void checkProtectsNode(String nodePath) throws RepositoryException {
+ if (session.nodeExists(nodePath)) {
+ NodeImpl n = (NodeImpl) session.getNode(nodePath);
+ if (n.isNodeType(NT_REP_ACL) || n.isNodeType(NT_REP_ACE)) {
+ throw new AccessControlException("Node " + nodePath + " defines ACL or ACE.");
+ }
+ }
+ }
+
+ /**
+ * Check if the specified policy can be set or removed at nodePath.
+ *
+ * @param nodePath
+ * @param policy
+ * @throws AccessControlException
+ */
+ private void checkValidPolicy(String nodePath, AccessControlPolicy policy)
+ throws AccessControlException {
+ if (policy == null || !(policy instanceof ACLTemplate)) {
+ throw new AccessControlException("Attempt to set/remove invalid policy " + policy);
+ }
+ ACLTemplate acl = (ACLTemplate) policy;
+ if (!nodePath.equals(acl.getPath())) {
+ throw new AccessControlException("Policy " + policy + " is not applicable or does not apply to the node at " + nodePath);
+ }
+ }
+
+ /**
+ *
+ * @param principal
+ * @return
+ * @throws RepositoryException
+ */
+ String getPathToAcNode(Principal principal) throws RepositoryException {
+ StringBuffer princPath = new StringBuffer(acRootPath);
+ if (principal instanceof ItemBasedPrincipal) {
+ princPath.append(((ItemBasedPrincipal) principal).getPath());
+ } else {
+ princPath.append("/");
+ princPath.append(Text.escapeIllegalJcrChars(principal.getName()));
+ }
+ return princPath.toString();
+ }
+
+ private Principal getPrincipal(String pathToACNode) throws RepositoryException {
+ String name = Text.unescapeIllegalJcrChars(Text.getName(pathToACNode));
+ PrincipalManager pMgr = session.getPrincipalManager();
+ if (!pMgr.hasPrincipal(name)) {
+ throw new AccessControlException("Unknown principal.");
+ }
+ return pMgr.getPrincipal(name);
+ }
+
+ /**
+ *
+ * @param node
+ * @return
+ * @throws RepositoryException
+ */
+ private boolean isAccessControlled(NodeImpl node) throws RepositoryException {
+ return node.isNodeType(NT_REP_ACCESS_CONTROL) && node.hasNode(N_POLICY);
+ }
+
+ /**
+ *
+ * @param acNode
+ * @return
+ * @throws RepositoryException
+ */
+ private AccessControlPolicy createTemplate(NodeImpl acNode) throws RepositoryException {
+ if (!acNode.isNodeType(NT_REP_ACCESS_CONTROL)) {
+ throw new RepositoryException("Expected node of type rep:AccessControl.");
+ }
+
+ Principal principal;
+ String principalName = Text.unescapeIllegalJcrChars(acNode.getName());
+ PrincipalManager pMgr = ((SessionImpl) acNode.getSession()).getPrincipalManager();
+ if (pMgr.hasPrincipal(principalName)) {
+ principal = pMgr.getPrincipal(principalName);
+ } else {
+ log.warn("Principal with name " + principalName + " unknown to PrincipalManager.");
+ // TODO: rather throw?
+ principal = new PrincipalImpl(principalName);
+ }
+ return new ACLTemplate(principal, acNode);
+ }
+
+ /**
+ * Create a unique valid name for the Permission nodes to be save.
+ *
+ * @param node a name for the child is resolved
+ * @param name if missing the {@link #DEFAULT_ACE_NAME} is taken
+ * @return
+ * @throws RepositoryException
+ */
+ protected static Name getUniqueNodeName(Node node, String name) throws RepositoryException {
+ if (name == null) {
+ name = DEFAULT_ACE_NAME;
+ } else {
+ try {
+ NameParser.checkFormat(name);
+ } catch (NameException e) {
+ name = DEFAULT_ACE_NAME;
+ log.debug("Invalid path name for Permission: " + name + ".");
+ }
+ }
+ int i=0;
+ String check = name;
+ while (node.hasNode(check)) {
+ check = name + i;
+ i++;
+ }
+ return ((SessionImpl) node.getSession()).getQName(check);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java?rev=689499&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java Wed Aug 27 08:12:04 2008
@@ -0,0 +1,441 @@
+/*
+ * $Id$
+ *
+ * Copyright 1997-2005 Day Management AG
+ * Barfuesserplatz 6, 4001 Basel, Switzerland
+ * All Rights Reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * Day Management AG, ("Confidential Information"). You shall not
+ * disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into
+ * with Day.
+ */
+package org.apache.jackrabbit.core.security.authorization.principalbased;
+
+import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
+import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
+import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
+import org.apache.jackrabbit.core.security.authorization.UnmodifiableAccessControlList;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.ItemImpl;
+import org.apache.jackrabbit.core.observation.SynchronousEventListener;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.Privilege;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.ValueFactory;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.EventIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.security.Principal;
+
+/**
+ * <code>CombinedProvider</code>...
+ */
+public class ACLProvider extends AbstractAccessControlProvider implements AccessControlConstants {
+
+ private static Logger log = LoggerFactory.getLogger(ACLProvider.class);
+
+ // TODO: add means to show effective-policy to a user.
+
+ private ACLEditor editor;
+ private NodeImpl acRoot;
+
+ //-------------------------------------------------< AccessControlUtils >---
+ /**
+ * @see AccessControlUtils#isAcItem(Path)
+ */
+ public boolean isAcItem(Path absPath) throws RepositoryException {
+ Path.Element[] elems = absPath.getElements();
+ for (int i = 0; i < elems.length; i++) {
+ if (N_POLICY.equals(elems[i].getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see AccessControlUtils#isAcItem(ItemImpl)
+ */
+ public boolean isAcItem(ItemImpl item) throws RepositoryException {
+ NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent());
+ return n.isNodeType(NT_REP_ACL) || n.isNodeType(NT_REP_ACE);
+ }
+
+ //----------------------------------------------< AccessControlProvider >---
+ /**
+ * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
+ */
+ public void init(Session systemSession, Map configuration) throws RepositoryException {
+ super.init(systemSession, configuration);
+
+ NodeImpl root = (NodeImpl) session.getRootNode();
+ if (root.hasNode(N_ACCESSCONTROL)) {
+ acRoot = root.getNode(N_ACCESSCONTROL);
+ if (!acRoot.isNodeType(NT_REP_ACCESS_CONTROL)) {
+ throw new RepositoryException("Error while initializing Access Control Provider: Found ac-root to be wrong node type " + acRoot.getPrimaryNodeType().getName());
+ }
+ } else {
+ acRoot = root.addNode(N_ACCESSCONTROL, NT_REP_ACCESS_CONTROL, null);
+ }
+
+ editor = new ACLEditor(session, resolver.getQPath(acRoot.getPath()));
+ if (!configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS)) {
+ try {
+ log.info("Install initial permissions: ...");
+
+ ValueFactory vf = session.getValueFactory();
+ Map restrictions = new HashMap();
+ restrictions.put(session.getJCRName(ACLTemplate.P_NODE_PATH), vf.createValue(root.getPath(), PropertyType.PATH));
+ restrictions.put(session.getJCRName(ACLTemplate.P_GLOB), vf.createValue(GlobPattern.WILDCARD_ALL));
+
+ PrincipalManager pMgr = session.getPrincipalManager();
+ AccessControlManager acMgr = session.getAccessControlManager();
+ Principal administrators;
+ String pName = SecurityConstants.ADMINISTRATORS_NAME;
+ if (pMgr.hasPrincipal(pName)) {
+ administrators = pMgr.getPrincipal(pName);
+ } else {
+ log.warn("Administrators principal group is missing.");
+ administrators = new PrincipalImpl(pName);
+ }
+ AccessControlPolicy[] acls = editor.editAccessControlPolicies(administrators);
+ ACLTemplate acl = (ACLTemplate) acls[0];
+ if (acl.isEmpty()) {
+ log.info("... Privilege.ALL for administrators principal.");
+ acl.addEntry(administrators,
+ new Privilege[] {acMgr.privilegeFromName(Privilege.JCR_ALL)},
+ true, restrictions);
+ editor.setPolicy(acl.getPath(), acl);
+ } else {
+ log.info("... policy for administrators principal already present.");
+ }
+
+ Principal everyone = pMgr.getEveryone();
+ acls = editor.editAccessControlPolicies(everyone);
+ acl = (ACLTemplate) acls[0];
+ if (acl.isEmpty()) {
+ log.info("... Privilege.READ for everyone principal.");
+ acl.addEntry(everyone,
+ new Privilege[] {acMgr.privilegeFromName(Privilege.JCR_READ)},
+ true, restrictions);
+ editor.setPolicy(acl.getPath(), acl);
+ } else {
+ log.info("... policy for everyone principal already present.");
+ }
+
+ session.save();
+ log.info("... done.");
+ } catch (RepositoryException e) {
+ log.error("Failed to set-up minimal access control for root node of workspace " + session.getWorkspace().getName());
+ session.getRootNode().refresh(false);
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * @see AccessControlProvider#getEffectivePolicies(Path)
+ */
+ public AccessControlPolicy[] getEffectivePolicies(Path absPath)
+ throws ItemNotFoundException, RepositoryException {
+ AccessControlPolicy[] tmpls = editor.getPolicies(session.getJCRPath(absPath));
+ AccessControlPolicy[] effectives = new AccessControlPolicy[tmpls.length];
+ for (int i = 0; i < tmpls.length; i++) {
+ effectives[i] = new UnmodifiableAccessControlList((ACLTemplate) tmpls[i]);
+ }
+ return effectives;
+ }
+
+ /**
+ * @see AccessControlProvider#getEditor(Session)
+ */
+ public AccessControlEditor getEditor(Session editingSession) {
+ checkInitialized();
+ if (editingSession instanceof SessionImpl) {
+ try {
+ return new ACLEditor((SessionImpl) editingSession, session.getQPath(acRoot.getPath()));
+ } catch (RepositoryException e) {
+ // should never get here
+ log.error("Internal error: ", e.getMessage());
+ }
+ }
+
+ log.debug("Unable to build access control editor " + ACLEditor.class.getName() + ".");
+ return null;
+ }
+
+ /**
+ * @see AccessControlProvider#compilePermissions(Set)
+ */
+ public CompiledPermissions compilePermissions(Set principals) throws RepositoryException {
+ checkInitialized();
+ if (isAdminOrSystem(principals)) {
+ return getAdminPermissions();
+ } else if (isReadOnly(principals)) {
+ return getReadOnlyPermissions();
+ } else {
+ return new ACLProvider.CompiledPermissionImpl(principals);
+ }
+ }
+
+ /**
+ * @see AccessControlProvider#canAccessRoot(Set)
+ */
+ public boolean canAccessRoot(Set principals) throws RepositoryException {
+ checkInitialized();
+ if (isAdminOrSystem(principals)) {
+ return true;
+ } else {
+ CompiledPermissions cp = new CompiledPermissionImpl(principals, false);
+ return cp.grants(PathFactoryImpl.getInstance().getRootPath(), Permission.READ);
+ }
+ }
+
+ //-----------------------------------------------------< CompiledPolicy >---
+ /**
+ *
+ */
+ private class CompiledPermissionImpl extends AbstractCompiledPermissions
+ implements SynchronousEventListener {
+
+ private final Set principals;
+ private final Set acPaths;
+ private ACLProvider.Entries entries;
+
+ /**
+ * @param principals
+ * @throws RepositoryException
+ */
+ private CompiledPermissionImpl(Set principals) throws RepositoryException {
+ this(principals, true);
+ }
+
+ /**
+ * @param principals
+ * @throws RepositoryException
+ */
+ private CompiledPermissionImpl(Set principals, boolean listenToEvents) throws RepositoryException {
+
+ this.principals = principals;
+ acPaths = new HashSet(principals.size());
+ entries = reload();
+
+ // TODO: describe
+ if (listenToEvents) {
+ int events = Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED |
+ Event.PROPERTY_REMOVED | Event.NODE_ADDED | Event.NODE_REMOVED;
+ String[] ntNames = new String[] {
+ session.getJCRName(NT_REP_ACE)
+ };
+ observationMgr.addEventListener(this, events, acRoot.getPath(), true, null, ntNames, false);
+ }
+ }
+
+ //------------------------------------< AbstractCompiledPermissions >---
+ /**
+ * @see AbstractCompiledPermissions#buildResult(Path)
+ */
+ protected synchronized Result buildResult(Path absPath) throws RepositoryException {
+ if (!absPath.isAbsolute()) {
+ throw new RepositoryException("Absolute path expected.");
+ }
+
+ boolean isAcItem = isAcItem(absPath);
+ String jcrPath = session.getJCRPath(absPath);
+
+ // retrieve principal-based permissions and privileges
+ Result result;
+ if (session.itemExists(jcrPath)) {
+ Item item = session.getItem(jcrPath);
+ result = entries.getResult(item, item.getPath(), isAcItem);
+ } else {
+ result = entries.getResult(null, jcrPath, isAcItem);
+ }
+ return result;
+ }
+
+ //--------------------------------------------< CompiledPermissions >---
+ /**
+ * @see CompiledPermissions#close()
+ */
+ public void close() {
+ try {
+ observationMgr.removeEventListener(this);
+ } catch (RepositoryException e) {
+ log.debug("Unable to unregister listener: ", e.getMessage());
+ }
+ super.close();
+ }
+
+ //--------------------------------------------------< EventListener >---
+ /**
+ * @see EventListener#onEvent(EventIterator)
+ */
+ public synchronized void onEvent(EventIterator events) {
+ try {
+ boolean reload = false;
+ while (events.hasNext() && !reload) {
+ Event ev = events.nextEvent();
+ String path = ev.getPath();
+ // only invalidate cache if any of the events affects the
+ // nodes defining permissions for the principals.
+ switch (ev.getType()) {
+ case Event.NODE_ADDED:
+ case Event.NODE_REMOVED:
+ reload = acPaths.contains(Text.getRelativeParent(path, 2));
+ break;
+ case Event.PROPERTY_ADDED:
+ case Event.PROPERTY_CHANGED:
+ case Event.PROPERTY_REMOVED:
+ reload = acPaths.contains(Text.getRelativeParent(path, 3));
+ break;
+ default:
+ // illegal event-type: should never occur. ignore
+ break;
+ }
+ }
+ // eventually reload the ACL and clear the cache
+ if (reload) {
+ clearCache();
+ // reload the acl
+ entries = reload();
+ }
+ } catch (RepositoryException e) {
+ // should never get here
+ log.warn("Internal error: ", e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @return
+ * @throws RepositoryException
+ */
+ private ACLProvider.Entries reload() throws RepositoryException {
+ // reload the paths
+ acPaths.clear();
+
+ // acNodes must be ordered in the same order as the principals
+ // in order to obtain proper acl-evalution in case the given
+ // principal-set is ordered.
+ List allACEs = new ArrayList();
+ // build acl-hierarchy assuming that principal-order determines the
+ // acl-inheritance.
+ for (Iterator it = principals.iterator(); it.hasNext();) {
+ Principal princ = (Principal) it.next();
+ ACLTemplate acl = editor.getACL(princ);
+ if (acl == null || acl.isEmpty()) {
+ acPaths.add(editor.getPathToAcNode(princ));
+ } else {
+ // retrieve the ACEs from the node
+ AccessControlEntry[] aces = (AccessControlEntry[]) acl.getAccessControlEntries();
+ allACEs.addAll(Arrays.asList(aces));
+ acPaths.add(acl.getPath());
+ }
+ }
+
+ return new ACLProvider.Entries(allACEs);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * Utility class that raps a list of access control entries and evaluates
+ * them for a specified item/path.
+ */
+ private class Entries {
+
+ private final List entries;
+
+ /**
+ *
+ * @param entries
+ */
+ private Entries(List entries) {
+ this.entries = entries;
+ }
+
+ /**
+ * Loop over all entries and evaluate allows/denies for those matching
+ * the given jcrPath.
+ *
+ * @param target Existing target item for which the permissions will be
+ * evaluated or <code>null</code>.
+ * @param targetPath Path used for the evaluation; pointing to an
+ * existing or non-existing item.
+ * @param isAcItem
+ * @return
+ * @throws RepositoryException
+ */
+ private AbstractCompiledPermissions.Result getResult(Item target,
+ String targetPath,
+ boolean isAcItem) throws RepositoryException {
+ int allows = Permission.NONE;
+ int denies = Permission.NONE;
+ int allowPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
+ int denyPrivileges = PrivilegeRegistry.NO_PRIVILEGE;
+ int parentAllows = PrivilegeRegistry.NO_PRIVILEGE;
+ int parentDenies = PrivilegeRegistry.NO_PRIVILEGE;
+
+ String parentPath = Text.getRelativeParent(targetPath, 1);
+ for (Iterator it = entries.iterator(); it.hasNext() && allows != Permission.ALL;) {
+ ACLTemplate.Entry entr = (ACLTemplate.Entry) it.next();
+ int privs = entr.getPrivilegeBits();
+
+ if (!"".equals(parentPath) && entr.matches(parentPath)) {
+ if (entr.isAllow()) {
+ parentAllows |= Permission.diff(privs, parentDenies);
+ } else {
+ parentDenies |= Permission.diff(privs, parentAllows);
+ }
+ }
+
+ boolean matches = (target != null) ? entr.matches(target) : entr.matches(targetPath);
+ if (matches) {
+ if (entr.isAllow()) {
+ allowPrivileges |= Permission.diff(privs, denyPrivileges);
+ int permissions = Permission.calculatePermissions(allowPrivileges, parentAllows, true, isAcItem);
+ allows |= Permission.diff(permissions, denies);
+ } else {
+ denyPrivileges |= Permission.diff(privs, allowPrivileges);
+ int permissions = Permission.calculatePermissions(denyPrivileges, parentDenies, false, isAcItem);
+ denies |= Permission.diff(permissions, allows);
+ }
+ }
+ }
+ return new AbstractCompiledPermissions.Result(allows, denies, allowPrivileges, denyPrivileges);
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url