jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r1407399 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak: security/privilege/ spi/security/privilege/
Date Fri, 09 Nov 2012 09:36:52 GMT
Author: angela
Date: Fri Nov  9 09:36:51 2012
New Revision: 1407399

URL: http://svn.apache.org/viewvc?rev=1407399&view=rev
Log:
OAK-64 : Privilege Management (WIP)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ReadOnlyPrivilegeManager.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeDefinitionProvider.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConfigurationImpl.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/PrivilegeDefinitionWriter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeConfiguration.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConfigurationImpl.java?rev=1407399&r1=1407398&r2=1407399&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConfigurationImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConfigurationImpl.java
Fri Nov  9 09:36:51 2012
@@ -28,22 +28,22 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConfiguration;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinitionProvider;
 
 /**
  * PrivilegeConfigurationImpl... TODO
  */
 public class PrivilegeConfigurationImpl extends SecurityConfiguration.Default implements
PrivilegeConfiguration {
 
+    @Nonnull
     @Override
-    public PrivilegeDefinitionProvider getPrivilegeDefinitionProvider(ContentSession contentSession,
Root root) {
-        return new PrivilegeDefinitionProviderImpl(contentSession, root);
+    public PrivilegeManager getPrivilegeManager(Root root, NamePathMapper namePathMapper)
{
+        return new ReadOnlyPrivilegeManager(root, namePathMapper);
     }
 
     @Nonnull
     @Override
     public PrivilegeManager getPrivilegeManager(ContentSession contentSession, Root root,
NamePathMapper namePathMapper) {
-        return new PrivilegeManagerImpl(root, getPrivilegeDefinitionProvider(contentSession,
root), namePathMapper);
+        return new PrivilegeManagerImpl(root, namePathMapper, contentSession);
     }
 
     @Nonnull
@@ -52,9 +52,10 @@ public class PrivilegeConfigurationImpl 
         return new PrivilegeInitializer();
     }
 
+    @Nonnull
     @Override
     public List<ValidatorProvider> getValidatorProviders() {
         ValidatorProvider vp = new PrivilegeValidatorProvider();
         return Collections.singletonList(vp);
     }
-}
\ No newline at end of file
+}

Modified: 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=1407399&r1=1407398&r2=1407399&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java
Fri Nov  9 09:36:51 2012
@@ -16,36 +16,15 @@
  */
 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.annotation.CheckForNull;
 import javax.annotation.Nonnull;
-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.Root;
 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.spi.security.privilege.PrivilegeConstants.PRIVILEGES_PATH;
 import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_AGGREGATES;
@@ -95,177 +74,4 @@ class PrivilegeDefinitionReader {
 
         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 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.values().toArray(new PrivilegeDefinition[definitions.size()]);
-    }
-
-    //--------------------------------------------------------------------------
-    /**
-     * 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/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=1407399&r1=1407398&r2=1407399&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
Fri Nov  9 09:36:51 2012
@@ -43,7 +43,7 @@ class PrivilegeDefinitionWriter implemen
         writeDefinitions(Collections.singleton(definition));
     }
 
-    void writeDefinitions(Set<PrivilegeDefinition> definitions) throws RepositoryException
{
+    void writeDefinitions(Iterable<PrivilegeDefinition> definitions) throws RepositoryException
{
         try {
             // make sure the privileges path is defined
             Tree privilegesTree = root.getTree(PRIVILEGES_PATH);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java?rev=1407399&r1=1407398&r2=1407399&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
Fri Nov  9 09:36:51 2012
@@ -16,63 +16,37 @@
  */
 package org.apache.jackrabbit.oak.security.privilege;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import javax.jcr.InvalidItemStateException;
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
-import javax.jcr.security.AccessControlException;
 import javax.jcr.security.Privilege;
 
-import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinitionProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * {@code PrivilegeManager} implementation operating on the specified
- * {@code PrivilegeDefinitionProvider}.
+ * {@code PrivilegeManager} implementation reading from and storing privileges
+ * into the repository.
  */
-public class PrivilegeManagerImpl implements PrivilegeManager {
+public class PrivilegeManagerImpl extends ReadOnlyPrivilegeManager {
 
     /**
      * logger instance
      */
     private static final Logger log = LoggerFactory.getLogger(PrivilegeManagerImpl.class);
 
-    private final Root root;
-    private final NamePathMapper namePathMapper;
+    private final ContentSession contentSession;
 
-    private final PrivilegeDefinitionProvider provider;
-
-    public PrivilegeManagerImpl(Root root, PrivilegeDefinitionProvider provider, NamePathMapper
namePathMapper) {
-        this.root = root;
-        this.namePathMapper = namePathMapper;
-        this.provider = provider;
-    }
-
-    @Override
-    public Privilege[] getRegisteredPrivileges() throws RepositoryException {
-        Set<Privilege> privileges = new HashSet<Privilege>();
-        for (PrivilegeDefinition def : provider.getPrivilegeDefinitions()) {
-            privileges.add(new PrivilegeImpl(def));
-        }
-        return privileges.toArray(new Privilege[privileges.size()]);
-    }
-
-    @Override
-    public Privilege getPrivilege(String privilegeName) throws RepositoryException {
-        PrivilegeDefinition def = provider.getPrivilegeDefinition(getOakName(privilegeName));
-        if (def == null) {
-            throw new AccessControlException("No such privilege " + privilegeName);
-        } else {
-            return new PrivilegeImpl(def);
-        }
+    public PrivilegeManagerImpl(Root root, NamePathMapper namePathMapper, ContentSession
contentSession) {
+        super(root, namePathMapper);
+        this.contentSession = contentSession;
     }
 
     @Override
@@ -89,16 +63,16 @@ public class PrivilegeManagerImpl implem
             throw new NamespaceException("Invalid privilege name " + privilegeName);
         }
 
-        PrivilegeDefinition def = provider.registerDefinition(oakName, isAbstract, getOakNames(declaredAggregateNames));
-        return new PrivilegeImpl(def);
+        PrivilegeDefinition definition = new PrivilegeDefinitionImpl(oakName, isAbstract,
getOakNames(declaredAggregateNames));
+        PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(contentSession.getLatestRoot());
+        writer.writeDefinition(definition);
+
+        // refresh the current root to make sure the definition is visible
+        root.refresh();
+        return getPrivilege(definition);
     }
 
     //------------------------------------------------------------< private >---
-
-    private String getOakName(String jcrName) {
-        return namePathMapper.getOakName(jcrName);
-    }
-
     private Set<String> getOakNames(String[] jcrNames) throws RepositoryException {
         Set<String> oakNames;
         if (jcrNames == null || jcrNames.length == 0) {
@@ -115,83 +89,4 @@ public class PrivilegeManagerImpl implem
         }
         return oakNames;
     }
-
-    //--------------------------------------------------------------------------
-    /**
-     * Privilege implementation based on a {@link PrivilegeDefinition}.
-     */
-    private class PrivilegeImpl implements Privilege {
-
-        private final PrivilegeDefinition definition;
-
-        private PrivilegeImpl(PrivilegeDefinition definition) {
-            this.definition = definition;
-        }
-
-        //------------------------------------------------------< Privilege >---
-        @Override
-        public String getName() {
-            return getOakName(definition.getName());
-        }
-
-        @Override
-        public boolean isAbstract() {
-            return definition.isAbstract();
-        }
-
-        @Override
-        public boolean isAggregate() {
-            return !definition.getDeclaredAggregateNames().isEmpty();
-        }
-
-        @Override
-        public Privilege[] getDeclaredAggregatePrivileges() {
-            Set<String> declaredAggregateNames = definition.getDeclaredAggregateNames();
-            Set<Privilege> declaredAggregates = new HashSet<Privilege>(declaredAggregateNames.size());
-            for (String pName : declaredAggregateNames) {
-                try {
-                    declaredAggregates.add(getPrivilege(pName));
-                } catch (RepositoryException e) {
-                    log.warn("Error while retrieving privilege "+ pName +" contained in "
+ getName(), e.getMessage());
-                }
-            }
-            return declaredAggregates.toArray(new Privilege[declaredAggregates.size()]);
-        }
-
-        @Override
-        public Privilege[] getAggregatePrivileges() {
-            Set<Privilege> aggr = new HashSet<Privilege>();
-            for (Privilege decl : getDeclaredAggregatePrivileges()) {
-                aggr.add(decl);
-                if (decl.isAggregate()) {
-                    // TODO: defensive check to prevent circular aggregation that might occur
with inconsistent repositories
-                    aggr.addAll(Arrays.asList(decl.getAggregatePrivileges()));
-                }
-            }
-            return aggr.toArray(new Privilege[aggr.size()]);
-        }
-
-        //---------------------------------------------------------< Object >---
-        @Override
-        public int hashCode() {
-            return definition.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o == this) {
-                return true;
-            }
-            if (o instanceof PrivilegeImpl) {
-                return definition.equals(((PrivilegeImpl) o).definition);
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Privilege " + definition.getName();
-        }
-    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java?rev=1407399&r1=1407398&r2=1407399&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
Fri Nov  9 09:36:51 2012
@@ -18,12 +18,32 @@ package org.apache.jackrabbit.oak.securi
 
 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.spi.security.privilege.PrivilegeDefinition;
-import org.apache.jackrabbit.oak.util.TODO;
+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
@@ -37,27 +57,28 @@ public class PrivilegeMigrator {
         this.contentSession = contentSession;
     }
 
-    /**
-     *
-     * @throws RepositoryException
-     */
     public void migrateCustomPrivileges() throws RepositoryException {
-        PrivilegeDefinitionProviderImpl pr = new PrivilegeDefinitionProviderImpl(contentSession,
contentSession.getLatestRoot());
+        final Root root = contentSession.getLatestRoot();
+        PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(root);
         InputStream stream = null;
-        // TODO: order custom privileges such that validation succeeds.
         // FIXME: 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 {
-                // TODO: should get a proper namespace registry from somewhere
-                NamespaceRegistry nsRegistry =
-                        TODO.dummyImplementation().returnValue(null);
-                PrivilegeDefinition[] custom = PrivilegeDefinitionReader.readCustomDefinitons(stream,
nsRegistry);
-
-                for (PrivilegeDefinition def : custom) {
-                    pr.registerDefinition(def.getName(), def.isAbstract(), def.getDeclaredAggregateNames());
-                }
+                NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry() {
+                    @Override
+                    protected Root getWriteRoot() {
+                        return root;
+                    }
+
+                    @Override
+                    protected Tree getReadTree() {
+                        return root.getTree("/");
+                    }
+                };
+                Iterable<PrivilegeDefinition> custom = readCustomDefinitons(stream,
nsRegistry);
+                writer.writeDefinitions(custom);
             } catch (IOException e) {
                 throw new RepositoryException(e);
             } finally {
@@ -69,4 +90,177 @@ public class PrivilegeMigrator {
             }
         }
     }
+
+    /**
+     * 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
+     */
+    private static Iterable<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.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 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

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ReadOnlyPrivilegeManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ReadOnlyPrivilegeManager.java?rev=1407399&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ReadOnlyPrivilegeManager.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/ReadOnlyPrivilegeManager.java
Fri Nov  9 09:36:51 2012
@@ -0,0 +1,204 @@
+/*
+ * 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.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Read-Only {@code PrivilegeManager} implementation reading privilege definitions
+ * from the repository content.
+ *
+ * TODO: review if jcr:all should be present in the content as well (updated in the privilege
commit validator)
+ */
+public class ReadOnlyPrivilegeManager implements PrivilegeManager {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(ReadOnlyPrivilegeManager.class);
+
+    final Root root;
+    final NamePathMapper namePathMapper;
+
+    public ReadOnlyPrivilegeManager(Root root, NamePathMapper namePathMapper) {
+        this.root = root;
+        this.namePathMapper = namePathMapper;
+    }
+
+    @Override
+    public Privilege[] getRegisteredPrivileges() throws RepositoryException {
+        Set<Privilege> privileges = new HashSet<Privilege>();
+        for (PrivilegeDefinition def : getPrivilegeDefinitions()) {
+            privileges.add(getPrivilege(def));
+        }
+        return privileges.toArray(new Privilege[privileges.size()]);
+    }
+
+    @Override
+    public Privilege getPrivilege(String privilegeName) throws RepositoryException {
+        PrivilegeDefinition def = getPrivilegeDefinition(getOakName(privilegeName));
+        if (def == null) {
+            throw new AccessControlException("No such privilege " + privilegeName);
+        } else {
+            return getPrivilege(def);
+        }
+    }
+
+    @Override
+    public Privilege registerPrivilege(String privilegeName, boolean isAbstract,
+                                       String[] declaredAggregateNames) throws RepositoryException
{
+        throw new UnsupportedRepositoryOperationException("ReadOnly PrivilegeManager: Privilege
registration not supported");
+    }
+
+    //------------------------------------------------------------< private >---
+    @CheckForNull
+    String getOakName(String jcrName) {
+        return namePathMapper.getOakName(jcrName);
+    }
+
+    @Nonnull
+    Privilege getPrivilege(PrivilegeDefinition definition) {
+        return new PrivilegeImpl(definition);
+    }
+
+    @Nonnull
+    private PrivilegeDefinition[] getPrivilegeDefinitions() {
+        Map<String, PrivilegeDefinition> definitions = getReader().readDefinitions();
+        definitions.put(PrivilegeConstants.JCR_ALL, getJcrAllDefinition(definitions));
+        return definitions.values().toArray(new PrivilegeDefinition[definitions.size()]);
+    }
+
+    @CheckForNull
+    private PrivilegeDefinition getPrivilegeDefinition(String oakName) {
+        if (PrivilegeConstants.JCR_ALL.equals(oakName)) {
+            return getJcrAllDefinition(getReader().readDefinitions());
+        } else {
+            return getReader().readDefinition(oakName);
+        }
+    }
+
+    @Nonnull
+    private PrivilegeDefinitionReader getReader() {
+        return new PrivilegeDefinitionReader(root);
+    }
+
+    @Nonnull
+    private static PrivilegeDefinition getJcrAllDefinition(Map<String, PrivilegeDefinition>
definitions) {
+        return new PrivilegeDefinitionImpl(PrivilegeConstants.JCR_ALL, false, definitions.keySet());
+    }
+
+    //--------------------------------------------------------------------------
+    /**
+     * Privilege implementation based on a {@link org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition}.
+     */
+    private class PrivilegeImpl implements Privilege {
+
+        private final PrivilegeDefinition definition;
+
+        private PrivilegeImpl(PrivilegeDefinition definition) {
+            this.definition = definition;
+        }
+
+        //------------------------------------------------------< Privilege >---
+        @Override
+        public String getName() {
+            return namePathMapper.getJcrName(definition.getName());
+        }
+
+        @Override
+        public boolean isAbstract() {
+            return definition.isAbstract();
+        }
+
+        @Override
+        public boolean isAggregate() {
+            return !definition.getDeclaredAggregateNames().isEmpty();
+        }
+
+        @Override
+        public Privilege[] getDeclaredAggregatePrivileges() {
+            Set<String> declaredAggregateNames = definition.getDeclaredAggregateNames();
+            Set<Privilege> declaredAggregates = new HashSet<Privilege>(declaredAggregateNames.size());
+            for (String oakName : declaredAggregateNames) {
+                if (oakName.equals(definition.getName())) {
+                    log.warn("Found cyclic privilege aggregation -> ignore declared aggregate
" + oakName);
+                    continue;
+                }
+                PrivilegeDefinition def = getPrivilegeDefinition(oakName);
+                if (def != null) {
+                    declaredAggregates.add(getPrivilege(def));
+                } else {
+                    log.warn("Invalid privilege '{}' in declared aggregates of '{}'", oakName,
getName());
+                }
+            }
+            return declaredAggregates.toArray(new Privilege[declaredAggregates.size()]);
+        }
+
+        @Override
+        public Privilege[] getAggregatePrivileges() {
+            Set<Privilege> aggr = new HashSet<Privilege>();
+            for (Privilege decl : getDeclaredAggregatePrivileges()) {
+                aggr.add(decl);
+                if (decl.isAggregate()) {
+                    // TODO: defensive check to prevent circular aggregation that might occur
with inconsistent repositories
+                    aggr.addAll(Arrays.asList(decl.getAggregatePrivileges()));
+                }
+            }
+            return aggr.toArray(new Privilege[aggr.size()]);
+        }
+
+        //---------------------------------------------------------< Object >---
+        @Override
+        public int hashCode() {
+            return definition.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (o instanceof PrivilegeImpl) {
+                return definition.equals(((PrivilegeImpl) o).definition);
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Privilege " + definition.getName();
+        }
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeConfiguration.java?rev=1407399&r1=1407398&r2=1407399&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeConfiguration.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeConfiguration.java
Fri Nov  9 09:36:51 2012
@@ -30,8 +30,8 @@ import org.apache.jackrabbit.oak.spi.sec
 public interface PrivilegeConfiguration extends SecurityConfiguration {
 
     @Nonnull
-    PrivilegeDefinitionProvider getPrivilegeDefinitionProvider(ContentSession contentSession,
Root root);
+    PrivilegeManager getPrivilegeManager(Root root, NamePathMapper namePathMapper);
 
     @Nonnull
     PrivilegeManager getPrivilegeManager(ContentSession contentSession, Root root, NamePathMapper
namePathMapper);
-}
\ No newline at end of file
+}



Mime
View raw message