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 ju...@apache.org on 2014/01/14 17:32:05 UTC

svn commit: r1558101 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/ oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/

Author: jukka
Date: Tue Jan 14 16:32:05 2014
New Revision: 1558101

URL: http://svn.apache.org/r1558101
Log:
OAK-519: Migration of custom jr2.x privileges into OAK

Add Angela's PrivilegeMigrator to oak-upgrade.
Not integrated into the main RepositoryUpgrade class yet.

Added:
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java?rev=1558101&r1=1558100&r2=1558101&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java Tue Jan 14 16:32:05 2014
@@ -42,7 +42,7 @@ import org.apache.jackrabbit.oak.util.No
  * PrivilegeDefinitionWriter is responsible for writing privilege definitions
  * to the repository without applying any validation checks.
  */
-class PrivilegeDefinitionWriter implements PrivilegeConstants {
+public class PrivilegeDefinitionWriter implements PrivilegeConstants {
 
     /**
      * The internal names of all built-in privileges that are not aggregates.
@@ -71,7 +71,7 @@ class PrivilegeDefinitionWriter implemen
 
     private PrivilegeBits next;
 
-    PrivilegeDefinitionWriter(Root root) {
+    public PrivilegeDefinitionWriter(Root root) {
         this.root = root;
         this.bitsMgr = new PrivilegeBitsProvider(root);
         Tree privilegesTree = bitsMgr.getPrivilegesTree();
@@ -88,7 +88,7 @@ class PrivilegeDefinitionWriter implemen
      * @param definition The new privilege definition.
      * @throws RepositoryException If the definition can't be written.
      */
-    void writeDefinition(PrivilegeDefinition definition) throws RepositoryException {
+    public void writeDefinition(PrivilegeDefinition definition) throws RepositoryException {
         writeDefinitions(Collections.singleton(definition));
     }
 

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1558101&r1=1558100&r2=1558101&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java Tue Jan 14 16:32:05 2014
@@ -276,6 +276,7 @@ public class RepositoryUpgrade {
 
             Map<Integer, String> idxToPrefix = copyNamespaces(builder);
             copyNodeTypes(builder);
+            copyPrivileges(builder);
             copyVersionStore(builder, idxToPrefix);
             copyWorkspaces(builder, idxToPrefix);
 
@@ -378,6 +379,10 @@ public class RepositoryUpgrade {
         return properties;
     }
 
+    private void copyPrivileges(NodeBuilder root) throws RepositoryException {
+        // TODO
+    }
+
     private void copyNodeTypes(NodeBuilder root) throws RepositoryException {
         NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
         NodeBuilder system = root.child(JCR_SYSTEM);

Added: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java?rev=1558101&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java (added)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/PrivilegeMigrator.java Tue Jan 14 16:32:05 2014
@@ -0,0 +1,264 @@
+/*
+ * 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.upgrade.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+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.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.name.ReadWriteNamespaceRegistry;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeDefinitionWriter;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+import org.apache.jackrabbit.oak.spi.security.privilege.ImmutablePrivilegeDefinition;
+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;
+
+/**
+ * PrivilegeMigrator is a utility to migrate custom privilege definitions from
+ * a jackrabbit 2 project to oak.
+ * <p/>
+ * TODO: this is an initial draft of a migration tool from jr2 custom privileges
+ * TODO: to oak. might need to be adjusted once we have defined a upgrade path (see OAK-458)
+ */
+public class PrivilegeMigrator {
+
+    private final ContentSession contentSession;
+
+    public PrivilegeMigrator(ContentSession contentSession) {
+        this.contentSession = contentSession;
+    }
+
+    public void migrateCustomPrivileges(InputStream privilegeStream) throws RepositoryException {
+        final Root root = contentSession.getLatestRoot();
+        PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(root);
+        try {
+            NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry() {
+                @Override
+                protected Root getWriteRoot() {
+                    return root;
+                }
+
+                @Override
+                protected Tree getReadTree() {
+                    return root.getTree("/");
+                }
+            };
+            for (PrivilegeDefinition def : readCustomDefinitions(privilegeStream, nsRegistry)) {
+                writer.writeDefinition(def);
+            }
+        } catch (IOException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * 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 The stream from which 2.x privilege definitions
+     *                         should be read.
+     * @param nsRegistry       The namespace registry.
+     * @return The {@code PrivilegeDefinition}s contained in the stream.
+     * @throws RepositoryException If a name collisions is detected during
+     *                             parsing the custom privileges.
+     * @throws IOException         If another error occurs while reading from the
+     *                             custom privileges stream.
+     */
+    private static Iterable<PrivilegeDefinition> readCustomDefinitions(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);
+            }
+            definitions.put(privName, def);
+        }
+        return definitions.values();
+    }
+
+    //--------------------------------------------------------------------------
+
+    /**
+     * 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 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 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 ImmutablePrivilegeDefinition(name, isAbstract, aggrNames);
+            }
+
+            // could not parse into privilege definition
+            return null;
+        }
+
+        /**
+         * Create a new {@code DocumentBuilder}
+         *
+         * @return a new {@code DocumentBuilder}
+         * @throws ParserConfigurationException If an error occurs.
+         */
+        private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
+            DocumentBuilder builder = createFactory().newDocumentBuilder();
+            builder.setErrorHandler(new DefaultHandler());
+            return builder;
+        }
+
+        /**
+         * Update the specified nsRegistry mappings with the nsRegistry declarations
+         * defined by the given XML element.
+         *
+         * @param elem       An XML element.
+         * @param nsRegistry The namespace registry used to keep track of the
+         *                   namespace definitions present in the xml file.
+         * @throws javax.jcr.RepositoryException If error occurs.
+         */
+        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;
+        }
+    }
+
+}