You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2012/08/14 10:53:09 UTC
svn commit: r1372785 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/
oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/
oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/ oak...
Author: angela
Date: Tue Aug 14 08:53:08 2012
New Revision: 1372785
URL: http://svn.apache.org/viewvc?rev=1372785&view=rev
Log:
OAK-64 : Privilege Management (WIP)
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/TypeValidatorProvider.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeRegistry.java
jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/builtin_nodetypes.cnd
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeManagerImpl.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/TypeValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/TypeValidatorProvider.java?rev=1372785&r1=1372784&r2=1372785&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/TypeValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/TypeValidatorProvider.java Tue Aug 14 08:53:08 2012
@@ -21,6 +21,7 @@ import java.util.Set;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -94,6 +95,8 @@ public class TypeValidatorProvider imple
// Oak types are always available
types.add(MIX_REP_MERGE_CONFLICT);
+ types.add(PrivilegeConstants.NT_REP_PRIVILEGES);
+ types.add(PrivilegeConstants.NT_REP_PRIVILEGE);
// Find any extra types from /jcr:system/jcr:nodeTypes
NodeState system = after.getChildNode(JCR_SYSTEM);
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java?rev=1372785&r1=1372784&r2=1372785&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java Tue Aug 14 08:53:08 2012
@@ -23,9 +23,17 @@ import org.apache.jackrabbit.JcrConstant
*/
public interface PrivilegeConstants {
+ // constants for privilege serialization
String REP_PRIVILEGES = "rep:privileges";
String PRIVILEGES_PATH = '/' + JcrConstants.JCR_SYSTEM + '/' + REP_PRIVILEGES;
-
+
+ String NT_REP_PRIVILEGES = "rep:Privileges";
+ String NT_REP_PRIVILEGE = "rep:Privilege";
+
+ String REP_IS_ABSTRACT = "rep:isAbstract";
+ String REP_AGGREGATES = "rep:aggregates";
+
+ // Constants for privilege names
String JCR_READ = "jcr:read";
String JCR_MODIFY_PROPERTIES = "jcr:modifyProperties";
String JCR_ADD_CHILD_NODES = "jcr:addChildNodes";
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionImpl.java?rev=1372785&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionImpl.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionImpl.java Tue Aug 14 08:53:08 2012
@@ -0,0 +1,92 @@
+/*
+ * 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.oak.security.privilege;
+
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+
+/**
+ * PrivilegeDefinitionImpl... TODO
+ */
+class PrivilegeDefinitionImpl implements PrivilegeDefinition {
+
+ private final String name;
+ private final boolean isAbstract;
+ private final Set<String> declaredAggregateNames;
+
+ PrivilegeDefinitionImpl(String name, boolean isAbstract,
+ Set<String> declaredAggregateNames) {
+ this.name = name;
+ this.isAbstract = isAbstract;
+ this.declaredAggregateNames = declaredAggregateNames;
+ }
+
+ PrivilegeDefinitionImpl(String name, boolean isAbstract,
+ String... declaredAggregateNames) {
+ this(name, isAbstract, ImmutableSet.copyOf(declaredAggregateNames));
+ }
+
+ //------------------------------------------------< PrivilegeDefinition >---
+ @Nonnull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isAbstract() {
+ return isAbstract;
+ }
+
+ @Nonnull
+ @Override
+ public String[] getDeclaredAggregateNames() {
+ return declaredAggregateNames.toArray(new String[declaredAggregateNames.size()]);
+ }
+
+ //-------------------------------------------------------------< Object >---
+ @Override
+ public int hashCode() {
+ int result = name.hashCode();
+ result = 31 * result + (isAbstract ? 1 : 0);
+ result = 31 * result + declaredAggregateNames.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof PrivilegeDefinitionImpl) {
+ PrivilegeDefinitionImpl other = (PrivilegeDefinitionImpl) o;
+ return name.equals(other.name) &&
+ isAbstract == other.isAbstract &&
+ declaredAggregateNames.equals(other.declaredAggregateNames);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "PrivilegeDefinition: " + name;
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java?rev=1372785&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java Tue Aug 14 08:53:08 2012
@@ -0,0 +1,259 @@
+/*
+ * 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.oak.security.privilege;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import static org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants.PRIVILEGES_PATH;
+import static org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants.REP_AGGREGATES;
+import static org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants.REP_IS_ABSTRACT;
+
+
+/**
+ * Reads privilege definitions without applying any validation.
+ */
+class PrivilegeDefinitionReader {
+
+ private final ContentSession contentSession;
+
+ PrivilegeDefinitionReader(ContentSession contentSession) {
+ this.contentSession = contentSession;
+ }
+
+ Map<String, PrivilegeDefinition> readDefinitions() {
+ Map<String, PrivilegeDefinition> definitions = new HashMap<String, PrivilegeDefinition>();
+ Tree privilegesTree = contentSession.getCurrentRoot().getTree(PRIVILEGES_PATH);
+ if (privilegesTree != null) {
+ for (Tree child : privilegesTree.getChildren()) {
+ PrivilegeDefinition def = readDefinition(child);
+ definitions.put(def.getName(), def);
+ }
+ }
+ return definitions;
+ }
+
+ PrivilegeDefinition readDefinition(Tree definitionTree) {
+ NodeUtil n = new NodeUtil(definitionTree, contentSession);
+ String name = n.getName();
+ boolean isAbstract = n.getBoolean(REP_IS_ABSTRACT);
+ String[] declAggrNames = n.getStrings(REP_AGGREGATES);
+
+ return new PrivilegeDefinitionImpl(name, isAbstract, declAggrNames);
+ }
+
+ /**
+ * Reads privilege definitions for the specified {@code InputStream}. The
+ * aim of this method is to provide backwards compatibility with
+ * custom privilege definitions of Jackrabbit 2.x repositories. The caller
+ * is in charge of migrating the definitions.
+ *
+ * @param customPrivileges
+ * @param nsRegistry
+ * @return
+ * @throws RepositoryException
+ * @throws IOException
+ */
+ static Map<String, PrivilegeDefinition> readCustomDefinitons(InputStream customPrivileges,
+ NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
+ Map<String, PrivilegeDefinition> definitions = new LinkedHashMap<String, PrivilegeDefinition>();
+ InputSource src = new InputSource(customPrivileges);
+ for (PrivilegeDefinition def : PrivilegeXmlHandler.readDefinitions(src, nsRegistry)) {
+ String privName = def.getName();
+ if (definitions.containsKey(privName)) {
+ throw new RepositoryException("Duplicate entry for custom privilege with name " + privName.toString());
+ }
+ definitions.put(privName, def);
+ }
+ return definitions;
+ }
+
+
+
+ //--------------------------------------------------------------------------
+ /**
+ * The {@code PrivilegeXmlHandler} loads privilege definitions from a XML
+ * document using the following format:
+ * <pre>
+ * <!DOCTYPE privileges [
+ * <!ELEMENT privileges (privilege)+>
+ * <!ELEMENT privilege (contains)+>
+ * <!ATTLIST privilege abstract (true|false) false>
+ * <!ATTLIST privilege name NMTOKEN #REQUIRED>
+ * <!ELEMENT contains EMPTY>
+ * <!ATTLIST contains name NMTOKEN #REQUIRED>
+ * ]>
+ * </pre>
+ */
+ private static class PrivilegeXmlHandler {
+
+ private static final String TEXT_XML = "text/xml";
+ private static final String APPLICATION_XML = "application/xml";
+
+ private static final String XML_PRIVILEGES = "privileges";
+ private static final String XML_PRIVILEGE = "privilege";
+ private static final String XML_CONTAINS = "contains";
+
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_ABSTRACT = "abstract";
+
+ private static final String ATTR_XMLNS = "xmlns:";
+
+ private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = createFactory();
+
+ private static DocumentBuilderFactory createFactory() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setIgnoringComments(false);
+ factory.setIgnoringElementContentWhitespace(true);
+ return factory;
+ }
+
+ private static PrivilegeDefinition[] readDefinitions(InputSource input,
+ NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
+ try {
+ List<PrivilegeDefinition> defs = new ArrayList<PrivilegeDefinition>();
+
+ DocumentBuilder builder = createDocumentBuilder();
+ Document doc = builder.parse(input);
+ Element root = doc.getDocumentElement();
+ if (!XML_PRIVILEGES.equals(root.getNodeName())) {
+ throw new IllegalArgumentException("root element must be named 'privileges'");
+ }
+
+ updateNamespaceMapping(root, nsRegistry);
+
+ NodeList nl = root.getElementsByTagName(XML_PRIVILEGE);
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ PrivilegeDefinition def = parseDefinition(n, nsRegistry);
+ if (def != null) {
+ defs.add(def);
+ }
+ }
+ return defs.toArray(new PrivilegeDefinition[defs.size()]);
+
+ } catch (SAXException e) {
+ throw new RepositoryException(e);
+ } catch (ParserConfigurationException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Build a new {@code PrivilegeDefinition} from the given XML node.
+ * @param n the xml node storing the privilege definition.
+ * @param nsRegistry
+ * @return a new PrivilegeDefinition.
+ * @throws javax.jcr.RepositoryException
+ */
+ private static PrivilegeDefinition parseDefinition(Node n, NamespaceRegistry nsRegistry) throws RepositoryException {
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ Element elem = (Element) n;
+
+ updateNamespaceMapping(elem, nsRegistry);
+
+ String name = elem.getAttribute(ATTR_NAME);
+ boolean isAbstract = Boolean.parseBoolean(elem.getAttribute(ATTR_ABSTRACT));
+
+ Set<String> aggrNames = new HashSet<String>();
+ NodeList nodeList = elem.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node contains = nodeList.item(i);
+ if (isElement(n) && XML_CONTAINS.equals(contains.getNodeName())) {
+ String aggrName = ((Element) contains).getAttribute(ATTR_NAME);
+ if (aggrName != null) {
+ aggrNames.add(aggrName);
+ }
+ }
+ }
+ return new PrivilegeDefinitionImpl(name, isAbstract, aggrNames);
+ }
+
+ // could not parse into privilege definition
+ return null;
+ }
+
+ /**
+ * Create a new {@code DocumentBuilder}
+ *
+ * @return a new {@code DocumentBuilder}
+ * @throws ParserConfigurationException
+ */
+ private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
+ DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+ builder.setErrorHandler(new DefaultHandler());
+ return builder;
+ }
+
+ /**
+ * Update the specified nsRegistry mappings with the nsRegistry declarations
+ * defined by the given XML element.
+ *
+ * @param elem
+ * @param nsRegistry
+ * @throws javax.jcr.RepositoryException
+ */
+ private static void updateNamespaceMapping(Element elem, NamespaceRegistry nsRegistry) throws RepositoryException {
+ NamedNodeMap attributes = elem.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Attr attr = (Attr) attributes.item(i);
+ if (attr.getName().startsWith(ATTR_XMLNS)) {
+ String prefix = attr.getName().substring(ATTR_XMLNS.length());
+ String uri = attr.getValue();
+ nsRegistry.registerNamespace(prefix, uri);
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given XML node is an element.
+ *
+ * @param n
+ * @return {@code true} if the given XML node is an element; {@code false} otherwise.
+ */
+ private static boolean isElement(Node n) {
+ return n.getNodeType() == Node.ELEMENT_NODE;
+ }
+ }
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeRegistry.java?rev=1372785&r1=1372784&r2=1372785&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeRegistry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeRegistry.java Tue Aug 14 08:53:08 2012
@@ -16,26 +16,40 @@
*/
package org.apache.jackrabbit.oak.security.privilege;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
-
import javax.annotation.Nonnull;
+import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.ContentSession;
-import org.apache.jackrabbit.oak.util.TODO;
+import org.apache.jackrabbit.oak.api.CoreValueFactory;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.core.DefaultConflictHandler;
+import org.apache.jackrabbit.oak.core.ReadOnlyTree;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceRegistryImpl;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeProvider;
-
-import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.oak.util.TODO;
+import org.apache.jackrabbit.util.Text;
/**
* PrivilegeProviderImpl... TODO
*/
-public class PrivilegeRegistry implements PrivilegeProvider, PrivilegeConstants {
+public class PrivilegeRegistry implements PrivilegeProvider, PrivilegeConstants, Validator {
private static final String[] SIMPLE_PRIVILEGES = new String[] {
JCR_READ, REP_ADD_PROPERTIES, REP_ALTER_PROPERTIES, REP_REMOVE_PROPERTIES,
@@ -56,13 +70,18 @@ public class PrivilegeRegistry implement
}
private final ContentSession contentSession;
+ private final PrivilegeDefinitionReader reader;
+
private final Map<String, PrivilegeDefinition> definitions = new HashMap<String, PrivilegeDefinition>();
- public PrivilegeRegistry(ContentSession contentSession) {
+ public PrivilegeRegistry(ContentSession contentSession) throws RepositoryException {
+
this.contentSession = contentSession;
+ this.reader = new PrivilegeDefinitionReader(contentSession);
// TODO: define if/how built-in privileges are reflected in the mk
// TODO: define where custom privileges are being stored.
+ // TODO: define if custom privileges are read with editing content session (thus enforcing read permissions)
for (String privilegeName : SIMPLE_PRIVILEGES) {
PrivilegeDefinition def = new PrivilegeDefinitionImpl(privilegeName, false);
@@ -74,12 +93,30 @@ public class PrivilegeRegistry implement
definitions.put(privilegeName, def);
}
- // TODO: jcr:all needs to be recalculated if custom privileges are registered
- definitions.put(JCR_ALL, new PrivilegeDefinitionImpl(JCR_ALL, false,
- JCR_READ, JCR_READ_ACCESS_CONTROL, JCR_MODIFY_ACCESS_CONTROL,
- JCR_VERSION_MANAGEMENT, JCR_LOCK_MANAGEMENT, JCR_LIFECYCLE_MANAGEMENT,
- JCR_RETENTION_MANAGEMENT, JCR_WORKSPACE_MANAGEMENT, JCR_NODE_TYPE_DEFINITION_MANAGEMENT,
- JCR_NAMESPACE_MANAGEMENT, REP_PRIVILEGE_MANAGEMENT, REP_WRITE));
+ CoreValueFactory vf = contentSession.getCoreValueFactory();
+ Root root = contentSession.getCurrentRoot();
+
+ Tree privilegesTree = root.getTree(PRIVILEGES_PATH);
+ if (privilegesTree == null) {
+ // backwards compatibility: read privileges from file system and update
+ // the content tree.
+ try {
+ NodeUtil system = new NodeUtil(root.getTree(JcrConstants.JCR_SYSTEM), contentSession);
+ NodeUtil privNode = system.addChild(REP_PRIVILEGES, NT_REP_PRIVILEGES);
+
+ migrateCustomPrivileges(privNode);
+
+ root.commit(DefaultConflictHandler.OURS);
+ } catch (IOException e) {
+ throw new RepositoryException(e);
+ } catch (CommitFailedException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ definitions.putAll(reader.readDefinitions());
+
+ updateJcrAllPrivilege();
}
//--------------------------------------------------< PrivilegeProvider >---
@@ -99,86 +136,125 @@ public class PrivilegeRegistry implement
final String privilegeName, final boolean isAbstract,
final Set<String> declaredAggregateNames)
throws RepositoryException {
- // TODO: check permission, validate and persist the custom definition
+ // TODO: add proper implementation including
+ // - permission check (possibly delegate to a commit validator),
+ // - validate definition (possibly delegate to commit validator)
+ // - persist the custom definition
+ // - recalculate jcr:all privilege
return TODO.dummyImplementation().call(new Callable<PrivilegeDefinition>() {
@Override
public PrivilegeDefinition call() throws Exception {
PrivilegeDefinition definition = new PrivilegeDefinitionImpl(
privilegeName, isAbstract,
new HashSet<String>(declaredAggregateNames));
- // TODO: update jcr:all
definitions.put(privilegeName, definition);
return definition;
}
});
}
+ //----------------------------------------------------------< Validator >---
+ @Override
+ public void propertyAdded(PropertyState after) throws CommitFailedException {
+ // no-op
+ }
- //--------------------------------------------------------------------------
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after) throws CommitFailedException {
+ throw new CommitFailedException("Attempt to modify existing privilege definition.");
+ }
- private static class PrivilegeDefinitionImpl implements PrivilegeDefinition {
+ @Override
+ public void propertyDeleted(PropertyState before) throws CommitFailedException {
+ throw new CommitFailedException("Attempt to modify existing privilege definition.");
+ }
- private final String name;
- private final boolean isAbstract;
- private final Set<String> declaredAggregateNames;
+ @Override
+ public Validator childNodeAdded(String name, NodeState after) throws CommitFailedException {
+ // the following characteristics are expected to be validated elsewhere:
+ // - name collisions (-> delegated to NodeTypeValidator since sms are not allowed)
+ // - name must be valid (-> delegated to NameValidator)
+
+ // name may not contain reserved namespace prefix
+ if (NamespaceConstants.RESERVED_PREFIXES.contains(Text.getNamespacePrefix(name))) {
+ String msg = "Failed to register custom privilege: Definition uses reserved namespace: " + name;
+ throw new CommitFailedException(new RepositoryException(msg));
+ }
+
+ // primary node type name must be rep:privilege
+ Tree tree = new ReadOnlyTree(null, name, after);
+ PropertyState primaryType = tree.getProperty(JcrConstants.JCR_PRIMARYTYPE);
+ if (primaryType == null || !NT_REP_PRIVILEGE.equals(primaryType.getValue().getString())) {
+ throw new CommitFailedException("Privilege definition must have primary node type set to rep:privilege");
+ }
+
+ // additional validation of the definition include:
+ PrivilegeDefinition def = reader.readDefinition(tree);
+ validateDefinition(def);
- private PrivilegeDefinitionImpl(String name, boolean isAbstract,
- Set<String> declaredAggregateNames) {
- this.name = name;
- this.isAbstract = isAbstract;
- this.declaredAggregateNames = declaredAggregateNames;
- }
+ // privilege definitions may not have child nodes.
+ return null;
+ }
- private PrivilegeDefinitionImpl(String name, boolean isAbstract,
- String... declaredAggregateNames) {
- this(name, isAbstract, ImmutableSet.copyOf(declaredAggregateNames));
- }
+ @Override
+ public Validator childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
+ throw new CommitFailedException("Attempt to modify existing privilege definition " + name);
+ }
- //--------------------------------------------< PrivilegeDefinition >---
- @Nonnull
- @Override
- public String getName() {
- return name;
- }
+ @Override
+ public Validator childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+ throw new CommitFailedException("Attempt to un-register privilege " + name);
+ }
- @Override
- public boolean isAbstract() {
- return isAbstract;
- }
+ //------------------------------------------------------------< private >---
- @Nonnull
- @Override
- public String[] getDeclaredAggregateNames() {
- return declaredAggregateNames.toArray(new String[declaredAggregateNames.size()]);
+ private void migrateCustomPrivileges(NodeUtil privilegesNode) throws RepositoryException, IOException, CommitFailedException {
+ InputStream stream = null;
+ // TODO: user proper path to jr2 custom privileges stored in fs
+ // jr2 used to be:
+ // new FileSystemResource(fs, "/privileges/custom_privileges.xml").getInputStream()
+ if (stream != null) {
+ try {
+ NamespaceRegistry nsRegistry = new NamespaceRegistryImpl(contentSession);
+ Map<String, PrivilegeDefinition> custom = PrivilegeDefinitionReader.readCustomDefinitons(stream, nsRegistry);
+ writeDefinitions(privilegesNode, custom);
+ } finally {
+ stream.close();
+ }
}
+ }
- //---------------------------------------------------------< Object >---
- @Override
- public int hashCode() {
- int result = name.hashCode();
- result = 31 * result + (isAbstract ? 1 : 0);
- result = 31 * result + declaredAggregateNames.hashCode();
- return result;
- }
+ private void updateJcrAllPrivilege() {
+ // TODO: add proper implementation taking custom privileges into account.
+ definitions.put(JCR_ALL, new PrivilegeDefinitionImpl(JCR_ALL, false,
+ JCR_READ, JCR_READ_ACCESS_CONTROL, JCR_MODIFY_ACCESS_CONTROL,
+ JCR_VERSION_MANAGEMENT, JCR_LOCK_MANAGEMENT, JCR_LIFECYCLE_MANAGEMENT,
+ JCR_RETENTION_MANAGEMENT, JCR_WORKSPACE_MANAGEMENT, JCR_NODE_TYPE_DEFINITION_MANAGEMENT,
+ JCR_NAMESPACE_MANAGEMENT, REP_PRIVILEGE_MANAGEMENT, REP_WRITE));
+ }
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
+ private void writeDefinitions(NodeUtil privilegesNode, Map<String, PrivilegeDefinition> definitions) {
+ for (PrivilegeDefinition def : definitions.values()) {
+ NodeUtil privNode = privilegesNode.addChild(def.getName(), NT_REP_PRIVILEGE);
+ if (def.isAbstract()) {
+ privNode.setBoolean(REP_IS_ABSTRACT, true);
}
- if (o instanceof PrivilegeDefinitionImpl) {
- PrivilegeDefinitionImpl other = (PrivilegeDefinitionImpl) o;
- return name.equals(other.name) &&
- isAbstract == other.isAbstract &&
- declaredAggregateNames.equals(other.declaredAggregateNames);
- } else {
- return false;
+ String[] declAggrNames = def.getDeclaredAggregateNames();
+ if (declAggrNames.length > 0) {
+ privNode.setNames(REP_AGGREGATES, def.getDeclaredAggregateNames());
}
}
+ }
- @Override
- public String toString() {
- return "PrivilegeDefinition: " + name;
- }
+ /**
+ *
+ * @param definition
+ */
+ private void validateDefinition(PrivilegeDefinition definition) {
+ // TODO
+ // - aggregate names refer to existing privileges
+ // - aggregate names do not create cyclic dependencies
+ // - aggregate names are not covered by an existing privilege definition
+ // -
}
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java?rev=1372785&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java Tue Aug 14 08:53:08 2012
@@ -0,0 +1,48 @@
+/*
+ * 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.oak.security.privilege;
+
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.spi.commit.SubtreeValidator;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
+import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants.REP_PRIVILEGES;
+
+/**
+ * PrivilegeValidatorProvider... TODO
+ */
+public class PrivilegeValidatorProvider implements ValidatorProvider {
+
+ private final ContentSession contentSession = null; // TODO
+
+ @Nonnull
+ @Override
+ public Validator getRootValidator(NodeState before, NodeState after) {
+ try {
+ // TODO check again...
+ return new SubtreeValidator(new PrivilegeRegistry(contentSession), JCR_SYSTEM, REP_PRIVILEGES);
+ } catch (RepositoryException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/builtin_nodetypes.cnd?rev=1372785&r1=1372784&r2=1372785&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/type/builtin_nodetypes.cnd Tue Aug 14 08:53:08 2012
@@ -502,6 +502,8 @@
// @since 2.0
+ jcr:configurations (rep:Configurations) = rep:Configurations protected ABORT
+ * (nt:base) = nt:base IGNORE
+ // @since oak 1.0
+ + rep:privileges (rep:Privileges) = rep:Privileges protected ABORT
/**
@@ -603,7 +605,7 @@
- rep:impersonators (STRING) protected multiple
[rep:User] > rep:Authorizable, rep:Impersonatable
- - rep:password (STRING) protected mandatory
+ - rep:password (STRING) protected
- rep:disabled (STRING) protected
[rep:Group] > rep:Authorizable
@@ -620,6 +622,24 @@
- * (WEAKREFERENCE) protected < 'rep:Authorizable'
// -----------------------------------------------------------------------------
+// Privilege Management
+// -----------------------------------------------------------------------------
+
+/**
+ * @since oak 1.0
+ */
+[rep:Privileges]
+ + * (rep:Privilege) = rep:Privilege protected ABORT
+
+/**
+ * @since oak 1.0
+ */
+[rep:Privilege]
+ - rep:isAbstract (BOOLEAN) protected
+ - rep:aggregates (NAME) protected multiple
+
+
+// -----------------------------------------------------------------------------
// J A C K R A B B I T R E T E N T I O N M A N A G E M E N T
// -----------------------------------------------------------------------------
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeManagerImpl.java?rev=1372785&r1=1372784&r2=1372785&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/privilege/PrivilegeManagerImpl.java Tue Aug 14 08:53:08 2012
@@ -45,7 +45,7 @@ public class PrivilegeManagerImpl implem
private final PrivilegeProvider provider;
private final SessionDelegate sessionDelegate;
- public PrivilegeManagerImpl(SessionDelegate sessionDelegate) {
+ public PrivilegeManagerImpl(SessionDelegate sessionDelegate) throws RepositoryException {
this.provider = new PrivilegeRegistry(sessionDelegate.getContentSession());
this.sessionDelegate = sessionDelegate;
}