package org.argeo.jackrabbit;
+import java.security.Principal;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import javax.jcr.Repository;
import javax.jcr.RepositoryException;
-import javax.jcr.security.AccessControlList;
-import javax.jcr.security.AccessControlPolicy;
-import javax.jcr.security.AccessControlPolicyIterator;
-import javax.jcr.security.Privilege;
+import javax.jcr.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.api.JackrabbitSession;
-import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.argeo.ArgeoException;
-import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.security.JcrAuthorizations;
/** Apply authorizations to a Jackrabbit repository. */
-public class JackrabbitAuthorizations {
+public class JackrabbitAuthorizations extends JcrAuthorizations {
private final static Log log = LogFactory
.getLog(JackrabbitAuthorizations.class);
- private Repository repository;
- private Executor systemExecutor;
-
- /**
- * key := privilege1,privilege2/path/to/node<br/>
- * value := group1,group2
- */
- private Map<String, String> groupPrivileges = new HashMap<String, String>();
-
- public void init() {
- Runnable action = new Runnable() {
- public void run() {
- JackrabbitSession session = null;
- try {
- session = (JackrabbitSession) repository.login();
- initAuthorizations(session);
- } catch (Exception e) {
- JcrUtils.discardQuietly(session);
- } finally {
- JcrUtils.logoutQuietly(session);
+ private List<String> groupPrefixes = new ArrayList<String>();
+
+ @Override
+ protected Principal getOrCreatePrincipal(Session session,
+ String principalName) throws RepositoryException {
+ UserManager um = ((JackrabbitSession) session).getUserManager();
+ Authorizable authorizable = um.getAuthorizable(principalName);
+ if (authorizable == null) {
+ groupPrefixes: for (String groupPrefix : groupPrefixes) {
+ if (principalName.startsWith(groupPrefix)) {
+ authorizable = um.createGroup(principalName);
+ log.info("Created group " + principalName);
+ break groupPrefixes;
}
}
- };
-
- if (systemExecutor != null)
- systemExecutor.execute(action);
- else
- action.run();
- }
-
- protected void initAuthorizations(JackrabbitSession session)
- throws RepositoryException {
- JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) session
- .getAccessControlManager();
- UserManager um = session.getUserManager();
-
- for (String privileges : groupPrivileges.keySet()) {
- String path = null;
- int slashIndex = privileges.indexOf('/');
- if (slashIndex == 0) {
- throw new ArgeoException("Privilege " + privileges
- + " badly formatted it starts with /");
- } else if (slashIndex > 0) {
- path = privileges.substring(slashIndex);
- privileges = privileges.substring(0, slashIndex);
- }
-
- if (path == null)
- path = "/";
-
- List<Privilege> privs = new ArrayList<Privilege>();
- for (String priv : privileges.split(",")) {
- privs.add(acm.privilegeFromName(priv));
- }
-
- String groupNames = groupPrivileges.get(privileges);
- for (String groupName : groupNames.split(",")) {
- Group group = (Group) um.getAuthorizable(groupName);
- if (group == null)
- group = um.createGroup(groupName);
- addPrivileges(session, group, path, privs);
- }
- }
- session.save();
- }
-
- public static void addPrivileges(JackrabbitSession session,
- Authorizable authorizable, String path, List<Privilege> privs)
- throws RepositoryException {
- JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) session
- .getAccessControlManager();
- AccessControlPolicy policy = null;
- AccessControlPolicyIterator policyIterator = acm
- .getApplicablePolicies(path);
- if (policyIterator.hasNext()) {
- policy = policyIterator.nextAccessControlPolicy();
- } else {
- AccessControlPolicy[] existingPolicies = acm.getPolicies(path);
- policy = existingPolicies[0];
- }
- if (policy instanceof AccessControlList) {
- ((AccessControlList) policy).addAccessControlEntry(
- authorizable.getPrincipal(),
- privs.toArray(new Privilege[privs.size()]));
- acm.setPolicy(path, policy);
+ if (authorizable == null)
+ throw new ArgeoException("Authorizable " + principalName
+ + " not found");
}
- if (log.isDebugEnabled())
- log.debug("Added privileges " + privs + " to " + authorizable
- + " on " + path);
+ return authorizable.getPrincipal();
}
- public void setGroupPrivileges(Map<String, String> groupPrivileges) {
- this.groupPrivileges = groupPrivileges;
+ public void setGroupPrefixes(List<String> groupsToCreate) {
+ this.groupPrefixes = groupsToCreate;
}
-
- public void setRepository(Repository repository) {
- this.repository = repository;
- }
-
- public void setSystemExecutor(Executor systemExecutor) {
- this.systemExecutor = systemExecutor;
- }
-
}
<!-- Workspace templates -->
<Workspaces rootPath="${rep.home}/workspaces"
- defaultWorkspace="${argeo.node.repo.defaultWorkspace}" configRootPath="/workspaces" />
+ defaultWorkspace="main" configRootPath="/workspaces" />
<Workspace name="${wsp.name}">
<FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
<PersistenceManager
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.Principal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import javax.jcr.observation.EventListener;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
import javax.jcr.version.VersionManager;
import org.apache.commons.io.IOUtils;
}
+ /** Logs the effective access control policies */
+ public static void logEffectiveAccessPolicies(Node node) {
+ try {
+ logEffectiveAccessPolicies(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ log.error("Cannot log effective access policies of " + node, e);
+ }
+ }
+
+ /** Logs the effective access control policies */
+ public static void logEffectiveAccessPolicies(Session session, String path) {
+ if (!log.isDebugEnabled())
+ return;
+
+ try {
+ AccessControlPolicy[] effectivePolicies = session
+ .getAccessControlManager().getEffectivePolicies(path);
+ if (effectivePolicies.length > 0) {
+ for (AccessControlPolicy policy : effectivePolicies) {
+ if (policy instanceof AccessControlList) {
+ AccessControlList acl = (AccessControlList) policy;
+ log.debug("Access control list for " + path + "\n"
+ + accessControlListSummary(acl));
+ }
+ }
+ } else {
+ log.debug("No effective access control policy for " + path);
+ }
+ } catch (RepositoryException e) {
+ log.error("Cannot log effective access policies of " + path, e);
+ }
+ }
+
+ /** Returns a human-readable summary of this access control list. */
+ public static String accessControlListSummary(AccessControlList acl) {
+ StringBuffer buf = new StringBuffer("");
+ try {
+ for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+ buf.append('\t').append(ace.getPrincipal().getName())
+ .append('\n');
+ for (Privilege priv : ace.getPrivileges())
+ buf.append("\t\t").append(priv.getName()).append('\n');
+ }
+ return buf.toString();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot write summary of " + acl, e);
+ }
+ }
+
/**
* Copies recursively the content of a node to another one. Do NOT copy the
* property values of {@link NodeType#MIX_CREATED} and
re);
}
}
+
+ /*
+ * SECURITY
+ */
+ /**
+ * Add privileges on a path to a {@link Principal}. The path must already
+ * exist.
+ */
+ public static void addPrivileges(Session session, String path,
+ Principal principal, List<Privilege> privs)
+ throws RepositoryException {
+ AccessControlManager acm = session.getAccessControlManager();
+ // search for an access control list
+ AccessControlList acl = null;
+ AccessControlPolicyIterator policyIterator = acm
+ .getApplicablePolicies(path);
+ if (policyIterator.hasNext()) {
+ while (policyIterator.hasNext()) {
+ AccessControlPolicy acp = policyIterator
+ .nextAccessControlPolicy();
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ } else {
+ AccessControlPolicy[] existingPolicies = acm.getPolicies(path);
+ for (AccessControlPolicy acp : existingPolicies) {
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ }
+
+ if (acl != null) {
+ acl.addAccessControlEntry(principal,
+ privs.toArray(new Privilege[privs.size()]));
+ acm.setPolicy(path, acl);
+ if (log.isDebugEnabled())
+ log.debug("Added privileges " + privs + " to " + principal
+ + " on " + path);
+ } else {
+ throw new ArgeoException("Don't know how to apply privileges "
+ + privs + " to " + principal + " on " + path);
+ }
+ }
+
}
--- /dev/null
+package org.argeo.jcr.security;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.util.security.SimplePrincipal;
+
+/** Apply authorizations to a JCR repository. */
+public class JcrAuthorizations implements Runnable {
+ private final static Log log = LogFactory.getLog(JcrAuthorizations.class);
+
+ private Repository repository;
+
+ /**
+ * key := privilege1,privilege2/path/to/node<br/>
+ * value := group1,group2,user1
+ */
+ private Map<String, String> principalPrivileges = new HashMap<String, String>();
+
+ public void run() {
+ Session session = null;
+ try {
+ session = repository.login();
+ initAuthorizations(session);
+ } catch (Exception e) {
+ JcrUtils.discardQuietly(session);
+ } finally {
+ JcrUtils.logoutQuietly(session);
+ }
+ }
+
+ /** @deprecated call {@link #run()} instead. */
+ @Deprecated
+ public void init() {
+ run();
+ }
+
+ protected void initAuthorizations(Session session)
+ throws RepositoryException {
+ AccessControlManager acm = session.getAccessControlManager();
+
+ for (String privileges : principalPrivileges.keySet()) {
+ String path = null;
+ int slashIndex = privileges.indexOf('/');
+ if (slashIndex == 0) {
+ throw new ArgeoException("Privilege " + privileges
+ + " badly formatted it starts with /");
+ } else if (slashIndex > 0) {
+ path = privileges.substring(slashIndex);
+ privileges = privileges.substring(0, slashIndex);
+ }
+
+ if (path == null)
+ path = "/";
+
+ List<Privilege> privs = new ArrayList<Privilege>();
+ for (String priv : privileges.split(",")) {
+ privs.add(acm.privilegeFromName(priv));
+ }
+
+ String principalNames = principalPrivileges.get(privileges);
+ for (String principalName : principalNames.split(",")) {
+ Principal principal = getOrCreatePrincipal(session,
+ principalName);
+ addPrivileges(session, principal, path, privs);
+ }
+ }
+ session.save();
+ }
+
+ /**
+ * Returns a {@link SimplePrincipal}, does not check whether it exists since
+ * such capabilities is not provided by the standard JCR API. Can be
+ * overridden to provide smarter handling
+ */
+ protected Principal getOrCreatePrincipal(Session session,
+ String principalName) throws RepositoryException {
+ return new SimplePrincipal(principalName);
+ }
+
+ public static void addPrivileges(Session session, Principal principal,
+ String path, List<Privilege> privs) throws RepositoryException {
+ AccessControlManager acm = session.getAccessControlManager();
+ // search for an access control list
+ AccessControlList acl = null;
+ AccessControlPolicyIterator policyIterator = acm
+ .getApplicablePolicies(path);
+ if (policyIterator.hasNext()) {
+ while (policyIterator.hasNext()) {
+ AccessControlPolicy acp = policyIterator
+ .nextAccessControlPolicy();
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ } else {
+ AccessControlPolicy[] existingPolicies = acm.getPolicies(path);
+ for (AccessControlPolicy acp : existingPolicies) {
+ if (acp instanceof AccessControlList)
+ acl = ((AccessControlList) acp);
+ }
+ }
+
+ if (acl != null) {
+ acl.addAccessControlEntry(principal,
+ privs.toArray(new Privilege[privs.size()]));
+ acm.setPolicy(path, acl);
+ if (log.isDebugEnabled())
+ log.debug("Added privileges " + privs + " to " + principal
+ + " on " + path);
+ } else {
+ throw new ArgeoException("Don't know how to apply privileges "
+ + privs + " to " + principal + " on " + path);
+ }
+ }
+
+ @Deprecated
+ public void setGroupPrivileges(Map<String, String> groupPrivileges) {
+ this.principalPrivileges = groupPrivileges;
+ }
+
+ public void setPrincipalPrivileges(Map<String, String> principalPrivileges) {
+ this.principalPrivileges = principalPrivileges;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ *
+ * Licensed 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.argeo.jcr;
+
+import java.io.File;
+
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.core.TransientRepository;
+import org.argeo.jcr.unit.AbstractJcrTestCase;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+/** Factorizes configuration of an in memory transient repository */
+public abstract class AbstractInternalJackrabbitTestCase extends
+ AbstractJcrTestCase {
+ protected File getRepositoryFile() throws Exception {
+ Resource res = new ClassPathResource(
+ "org/argeo/server/jcr/repository-memory.xml");
+ return res.getFile();
+ }
+
+ protected Repository createRepository() throws Exception {
+ Repository repository = new TransientRepository(getRepositoryFile(),
+ getHomeDir());
+ return repository;
+ }
+
+}
package org.argeo.jcr;
-import java.io.File;
-
import javax.jcr.Node;
-import javax.jcr.Repository;
-import org.apache.jackrabbit.core.TransientRepository;
import org.argeo.jcr.spring.BeanNodeMapper;
-import org.argeo.jcr.unit.AbstractJcrTestCase;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-public class MapperTest extends AbstractJcrTestCase {
+public class MapperTest extends AbstractInternalJackrabbitTestCase {
public void testSimpleObject() throws Exception {
SimpleObject mySo = new SimpleObject();
mySo.setInteger(100);
session().save();
JcrUtils.debug(node);
}
-
- protected File getRepositoryFile() throws Exception {
- Resource res = new ClassPathResource(
- "org/argeo/server/jcr/repository-h2.xml");
- return res.getFile();
- }
-
- protected Repository createRepository() throws Exception{
- Repository repository = new TransientRepository(getRepositoryFile(), getHomeDir());
- return repository;
- }
-
-
}
package org.argeo.jcr.tabular;
-import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.PropertyType;
-import javax.jcr.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.commons.cnd.CndImporter;
-import org.apache.jackrabbit.core.TransientRepository;
+import org.argeo.jcr.AbstractInternalJackrabbitTestCase;
import org.argeo.jcr.ArgeoNames;
import org.argeo.jcr.ArgeoTypes;
-import org.argeo.jcr.unit.AbstractJcrTestCase;
import org.argeo.util.tabular.TabularColumn;
import org.argeo.util.tabular.TabularRow;
import org.argeo.util.tabular.TabularRowIterator;
import org.argeo.util.tabular.TabularWriter;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-public class JcrTabularTest extends AbstractJcrTestCase {
+public class JcrTabularTest extends AbstractInternalJackrabbitTestCase {
private final static Log log = LogFactory.getLog(JcrTabularTest.class);
public void testWriteReadCsv() throws Exception {
log.debug("Read tabular content " + rowCount + " rows, "
+ columnCount + " columns");
}
-
- protected File getRepositoryFile() throws Exception {
- Resource res = new ClassPathResource(
- "org/argeo/server/jcr/repository-h2.xml");
- return res.getFile();
- }
-
- protected Repository createRepository() throws Exception {
- // JackrabbitContainer repo = new JackrabbitContainer();
- // repo.setHomeDirectory(getHomeDir());
- // repo.setConfiguration(new FileSystemResource(
- // getRepositoryFile()));
- // repo.setInMemory(true);
- // repo.set
- Repository repository = new TransientRepository(getRepositoryFile(),
- getHomeDir());
- return repository;
- }
-
}
package org.argeo.server.jcr;
-import java.io.File;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
-import javax.jcr.Repository;
-
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.jackrabbit.core.TransientRepository;
+import org.argeo.jcr.AbstractInternalJackrabbitTestCase;
import org.argeo.jcr.JcrResourceAdapter;
-import org.argeo.jcr.unit.AbstractJcrTestCase;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-public class JcrResourceAdapterTest extends AbstractJcrTestCase {
+public class JcrResourceAdapterTest extends AbstractInternalJackrabbitTestCase {
private static SimpleDateFormat sdf = new SimpleDateFormat(
"yyyyMMdd:hhmmss.SSS");
log.debug("TEAR DOWN");
super.tearDown();
}
-
- protected File getRepositoryFile() throws Exception {
- Resource res = new ClassPathResource(
- "org/argeo/server/jcr/repository-h2.xml");
- return res.getFile();
- }
-
- protected Repository createRepository() throws Exception {
- Repository repository = new TransientRepository(getRepositoryFile(),
- getHomeDir());
- return repository;
- }
-
}
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
+ "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
+<Repository>
+ <!-- File system and datastore -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
+
+ <!-- Workspace templates -->
+ <Workspaces rootPath="${rep.home}/workspaces"
+ defaultWorkspace="main" configRootPath="/workspaces" />
+ <Workspace name="${wsp.name}">
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+ <param name="blobFSBlockSize" value="1" />
+ </PersistenceManager>
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index" />
+ <param name="directoryManagerClass"
+ value="org.apache.jackrabbit.core.query.lucene.directory.RAMDirectoryManager" />
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
+ </SearchIndex>
+ </Workspace>
+
+ <!-- Versioning -->
+ <Versioning rootPath="${rep.home}/version">
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
+ <PersistenceManager
+ class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+ <param name="blobFSBlockSize" value="1" />
+ </PersistenceManager>
+ </Versioning>
+
+ <!-- Indexing -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index" />
+ <param name="directoryManagerClass"
+ value="org.apache.jackrabbit.core.query.lucene.directory.RAMDirectoryManager" />
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
+ </SearchIndex>
+
+ <!-- Security -->
+ <Security appName="Jackrabbit">
+ <SecurityManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleSecurityManager"
+ workspaceName="security" />
+ <AccessManager
+ class="org.apache.jackrabbit.core.security.simple.SimpleAccessManager" />
+ <LoginModule
+ class="org.apache.jackrabbit.core.security.simple.SimpleLoginModule">
+ <param name="anonymousId" value="anonymous" />
+ <param name="adminId" value="admin" />
+ </LoginModule>
+ </Security>
+</Repository>
\ No newline at end of file