jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject 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...
Date Tue, 14 Aug 2012 08:53:09 GMT
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>
+     *  &lt;!DOCTYPE privileges [
+     *  &lt;!ELEMENT privileges (privilege)+&gt;
+     *  &lt;!ELEMENT privilege (contains)+&gt;
+     *  &lt;!ATTLIST privilege abstract (true|false) false&gt;
+     *  &lt;!ATTLIST privilege name NMTOKEN #REQUIRED&gt;
+     *  &lt;!ELEMENT contains EMPTY&gt;
+     *  &lt;!ATTLIST contains name NMTOKEN #REQUIRED&gt;
+     * ]>
+     * </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;
     }



Mime
View raw message