You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2012/11/09 10:36:52 UTC
svn commit: r1407399 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak:
security/privilege/ spi/security/privilege/
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>
- * <!DOCTYPE privileges [
- * <!ELEMENT privileges (privilege)+>
- * <!ELEMENT privilege (contains)+>
- * <!ATTLIST privilege abstract (true|false) false>
- * <!ATTLIST privilege name NMTOKEN #REQUIRED>
- * <!ELEMENT contains EMPTY>
- * <!ATTLIST contains name NMTOKEN #REQUIRED>
- * ]>
- * </pre>
- */
- private static class PrivilegeXmlHandler {
-
- private static final String TEXT_XML = "text/xml";
- private static final String APPLICATION_XML = "application/xml";
-
- private static final String XML_PRIVILEGES = "privileges";
- private static final String XML_PRIVILEGE = "privilege";
- private static final String XML_CONTAINS = "contains";
-
- private static final String ATTR_NAME = "name";
- private static final String ATTR_ABSTRACT = "abstract";
-
- private static final String ATTR_XMLNS = "xmlns:";
-
- private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = createFactory();
-
- private static DocumentBuilderFactory createFactory() {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setIgnoringComments(false);
- factory.setIgnoringElementContentWhitespace(true);
- return factory;
- }
-
- private static PrivilegeDefinition[] readDefinitions(InputSource input,
- NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
- try {
- List<PrivilegeDefinition> defs = new ArrayList<PrivilegeDefinition>();
-
- DocumentBuilder builder = createDocumentBuilder();
- Document doc = builder.parse(input);
- Element root = doc.getDocumentElement();
- if (!XML_PRIVILEGES.equals(root.getNodeName())) {
- throw new IllegalArgumentException("root element must be named 'privileges'");
- }
-
- updateNamespaceMapping(root, nsRegistry);
-
- NodeList nl = root.getElementsByTagName(XML_PRIVILEGE);
- for (int i = 0; i < nl.getLength(); i++) {
- Node n = nl.item(i);
- PrivilegeDefinition def = parseDefinition(n, nsRegistry);
- if (def != null) {
- defs.add(def);
- }
- }
- return defs.toArray(new PrivilegeDefinition[defs.size()]);
-
- } catch (SAXException e) {
- throw new RepositoryException(e);
- } catch (ParserConfigurationException e) {
- throw new RepositoryException(e);
- }
- }
-
- /**
- * Build a new {@code PrivilegeDefinition} from the given XML node.
- * @param n the xml node storing the privilege definition.
- * @param nsRegistry
- * @return a new PrivilegeDefinition.
- * @throws javax.jcr.RepositoryException
- */
- private static PrivilegeDefinition parseDefinition(Node n, NamespaceRegistry nsRegistry) throws RepositoryException {
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- Element elem = (Element) n;
-
- updateNamespaceMapping(elem, nsRegistry);
-
- String name = elem.getAttribute(ATTR_NAME);
- boolean isAbstract = Boolean.parseBoolean(elem.getAttribute(ATTR_ABSTRACT));
-
- Set<String> aggrNames = new HashSet<String>();
- NodeList nodeList = elem.getChildNodes();
- for (int i = 0; i < nodeList.getLength(); i++) {
- Node contains = nodeList.item(i);
- if (isElement(n) && XML_CONTAINS.equals(contains.getNodeName())) {
- String aggrName = ((Element) contains).getAttribute(ATTR_NAME);
- if (aggrName != null) {
- aggrNames.add(aggrName);
- }
- }
- }
- return new PrivilegeDefinitionImpl(name, isAbstract, aggrNames);
- }
-
- // could not parse into privilege definition
- return null;
- }
-
- /**
- * Create a new {@code DocumentBuilder}
- *
- * @return a new {@code DocumentBuilder}
- * @throws ParserConfigurationException
- */
- private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
- DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- builder.setErrorHandler(new DefaultHandler());
- return builder;
- }
-
- /**
- * Update the specified nsRegistry mappings with the nsRegistry declarations
- * defined by the given XML element.
- *
- * @param elem
- * @param nsRegistry
- * @throws javax.jcr.RepositoryException
- */
- private static void updateNamespaceMapping(Element elem, NamespaceRegistry nsRegistry) throws RepositoryException {
- NamedNodeMap attributes = elem.getAttributes();
- for (int i = 0; i < attributes.getLength(); i++) {
- Attr attr = (Attr) attributes.item(i);
- if (attr.getName().startsWith(ATTR_XMLNS)) {
- String prefix = attr.getName().substring(ATTR_XMLNS.length());
- String uri = attr.getValue();
- nsRegistry.registerNamespace(prefix, uri);
- }
- }
- }
-
- /**
- * Returns {@code true} if the given XML node is an element.
- *
- * @param n
- * @return {@code true} if the given XML node is an element; {@code false} otherwise.
- */
- private static boolean isElement(Node n) {
- return n.getNodeType() == Node.ELEMENT_NODE;
- }
- }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/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>
+ * <!DOCTYPE privileges [
+ * <!ELEMENT privileges (privilege)+>
+ * <!ELEMENT privilege (contains)+>
+ * <!ATTLIST privilege abstract (true|false) false>
+ * <!ATTLIST privilege name NMTOKEN #REQUIRED>
+ * <!ELEMENT contains EMPTY>
+ * <!ATTLIST contains name NMTOKEN #REQUIRED>
+ * ]>
+ * </pre>
+ */
+ private static class PrivilegeXmlHandler {
+
+ private static final String TEXT_XML = "text/xml";
+ private static final String APPLICATION_XML = "application/xml";
+
+ private static final String XML_PRIVILEGES = "privileges";
+ private static final String XML_PRIVILEGE = "privilege";
+ private static final String XML_CONTAINS = "contains";
+
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_ABSTRACT = "abstract";
+
+ private static final String ATTR_XMLNS = "xmlns:";
+
+ private static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = createFactory();
+
+ private static DocumentBuilderFactory createFactory() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setIgnoringComments(false);
+ factory.setIgnoringElementContentWhitespace(true);
+ return factory;
+ }
+
+ private static PrivilegeDefinition[] readDefinitions(InputSource input,
+ NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
+ try {
+ List<PrivilegeDefinition> defs = new ArrayList<PrivilegeDefinition>();
+
+ DocumentBuilder builder = createDocumentBuilder();
+ Document doc = builder.parse(input);
+ Element root = doc.getDocumentElement();
+ if (!XML_PRIVILEGES.equals(root.getNodeName())) {
+ throw new IllegalArgumentException("root element must be named 'privileges'");
+ }
+
+ updateNamespaceMapping(root, nsRegistry);
+
+ NodeList nl = root.getElementsByTagName(XML_PRIVILEGE);
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ PrivilegeDefinition def = parseDefinition(n, nsRegistry);
+ if (def != null) {
+ defs.add(def);
+ }
+ }
+ return defs.toArray(new PrivilegeDefinition[defs.size()]);
+
+ } catch (SAXException e) {
+ throw new RepositoryException(e);
+ } catch (ParserConfigurationException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Build a new {@code PrivilegeDefinition} from the given XML node.
+ * @param n the xml node storing the privilege definition.
+ * @param nsRegistry
+ * @return a new PrivilegeDefinition.
+ * @throws javax.jcr.RepositoryException
+ */
+ private static PrivilegeDefinition parseDefinition(Node n, NamespaceRegistry nsRegistry) throws RepositoryException {
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ Element elem = (Element) n;
+
+ updateNamespaceMapping(elem, nsRegistry);
+
+ String name = elem.getAttribute(ATTR_NAME);
+ boolean isAbstract = Boolean.parseBoolean(elem.getAttribute(ATTR_ABSTRACT));
+
+ Set<String> aggrNames = new HashSet<String>();
+ NodeList nodeList = elem.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node contains = nodeList.item(i);
+ if (isElement(n) && XML_CONTAINS.equals(contains.getNodeName())) {
+ String aggrName = ((Element) contains).getAttribute(ATTR_NAME);
+ if (aggrName != null) {
+ aggrNames.add(aggrName);
+ }
+ }
+ }
+ return new PrivilegeDefinitionImpl(name, isAbstract, aggrNames);
+ }
+
+ // could not parse into privilege definition
+ return null;
+ }
+
+ /**
+ * Create a new {@code DocumentBuilder}
+ *
+ * @return a new {@code DocumentBuilder}
+ * @throws ParserConfigurationException
+ */
+ private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
+ DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+ builder.setErrorHandler(new DefaultHandler());
+ return builder;
+ }
+
+ /**
+ * Update the specified nsRegistry mappings with the nsRegistry declarations
+ * defined by the given XML element.
+ *
+ * @param elem
+ * @param nsRegistry
+ * @throws javax.jcr.RepositoryException
+ */
+ private static void updateNamespaceMapping(Element elem, NamespaceRegistry nsRegistry) throws RepositoryException {
+ NamedNodeMap attributes = elem.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Attr attr = (Attr) attributes.item(i);
+ if (attr.getName().startsWith(ATTR_XMLNS)) {
+ String prefix = attr.getName().substring(ATTR_XMLNS.length());
+ String uri = attr.getValue();
+ nsRegistry.registerNamespace(prefix, uri);
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given XML node is an element.
+ *
+ * @param n
+ * @return {@code true} if the given XML node is an element; {@code false} otherwise.
+ */
+ private static boolean isElement(Node n) {
+ return n.getNodeType() == Node.ELEMENT_NODE;
+ }
+ }
}
\ No newline at end of file
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
+}