X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=server%2Fruntime%2Forg.argeo.server.jcr%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fjcr%2FJcrUtils.java;h=fdc69214942fde0a57b9ffd679b789097fc78ca9;hb=7c4ea2803d8dd912e7751b85be4eeb1861905bde;hp=c847d5edd650b3b40fd757c00c8d12a0d86a1cb0;hpb=389a70ebf54ee69aef3f695c1b66957d5fe0f33e;p=lgpl%2Fargeo-commons.git diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index c847d5edd..fdc692149 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Mathieu Baudier + * Copyright (C) 2007-2012 Mathieu Baudier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.argeo.jcr; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; 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; @@ -36,6 +39,7 @@ import java.util.TreeMap; import javax.jcr.Binary; import javax.jcr.NamespaceRegistry; +import javax.jcr.NoSuchWorkspaceException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; @@ -51,12 +55,19 @@ import javax.jcr.nodetype.NodeType; 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; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; +import org.argeo.util.security.SimplePrincipal; /** Utility methods to simplify common JCR operations. */ public class JcrUtils implements ArgeoJcrConstants { @@ -504,6 +515,55 @@ public class JcrUtils implements ArgeoJcrConstants { } + /** 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 @@ -825,6 +885,73 @@ public class JcrUtils implements ArgeoJcrConstants { } } + /** + * Copy a file as an nt:file, assuming an nt:folder hierarchy. The session + * is NOT saved. + * + * @return the created file node + */ + public static Node copyFile(Node folderNode, File file) { + InputStream in = null; + try { + in = new FileInputStream(file); + return copyStreamAsFile(folderNode, file.getName(), in); + } catch (IOException e) { + throw new ArgeoException("Cannot copy file " + file + " under " + + folderNode, e); + } finally { + IOUtils.closeQuietly(in); + } + } + + /** Copy bytes as an nt:file */ + public static Node copyBytesAsFile(Node folderNode, String fileName, + byte[] bytes) { + InputStream in = null; + try { + in = new ByteArrayInputStream(bytes); + return copyStreamAsFile(folderNode, fileName, in); + } catch (Exception e) { + throw new ArgeoException("Cannot copy file " + fileName + " under " + + folderNode, e); + } finally { + IOUtils.closeQuietly(in); + } + } + + /** + * Copy a stream as an nt:file, assuming an nt:folder hierarchy. The session + * is NOT saved. + * + * @return the created file node + */ + public static Node copyStreamAsFile(Node folderNode, String fileName, + InputStream in) { + Binary binary = null; + try { + Node fileNode; + Node contentNode; + if (folderNode.hasNode(fileName)) { + fileNode = folderNode.getNode(fileName); + // we assume that the content node is already there + contentNode = fileNode.getNode(Node.JCR_CONTENT); + } else { + fileNode = folderNode.addNode(fileName, NodeType.NT_FILE); + contentNode = fileNode.addNode(Node.JCR_CONTENT, + NodeType.NT_RESOURCE); + } + binary = contentNode.getSession().getValueFactory() + .createBinary(in); + contentNode.setProperty(Property.JCR_DATA, binary); + return fileNode; + } catch (Exception e) { + throw new ArgeoException("Cannot create file node " + fileName + + " under " + folderNode, e); + } finally { + closeQuietly(binary); + } + } + /** * Creates depth from a string (typically a username) by adding levels based * on its first characters: "aBcD",2 => a/aB @@ -910,6 +1037,29 @@ public class JcrUtils implements ArgeoJcrConstants { } } + /** + * Login to a workspace with implicit credentials, creates the workspace + * with these credentials if it does not already exist. + */ + public static Session loginOrCreateWorkspace(Repository repository, + String workspaceName) throws RepositoryException { + Session workspaceSession = null; + Session defaultSession = null; + try { + try { + workspaceSession = repository.login(workspaceName); + } catch (NoSuchWorkspaceException e) { + // try to create workspace + defaultSession = repository.login(); + defaultSession.getWorkspace().createWorkspace(workspaceName); + workspaceSession = repository.login(workspaceName); + } + return workspaceSession; + } finally { + logoutQuietly(defaultSession); + } + } + /** Logs out the session, not throwing any exception, even if it is null. */ public static void logoutQuietly(Session session) { try { @@ -1307,4 +1457,61 @@ public class JcrUtils implements ArgeoJcrConstants { re); } } + + /* + * SECURITY + */ + + /** + * Convenience method for adding a single privilege to a principal (user or + * role), typically jcr:all + */ + public static void addPrivilege(Session session, String path, + String principal, String privilege) throws RepositoryException { + List privileges = new ArrayList(); + privileges.add(session.getAccessControlManager().privilegeFromName( + privilege)); + addPrivileges(session, path, new SimplePrincipal(principal), privileges); + } + + /** + * 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 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); + } + } + }