package org.exoplatform.platform.common.ext; import org.exoplatform.services.cms.link.LinkManager; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.jcr.access.AccessControlEntry; import org.exoplatform.services.jcr.access.PermissionType; import org.exoplatform.services.jcr.core.ExtendedNode; import org.exoplatform.services.jcr.core.ManageableRepository; import org.exoplatform.services.jcr.ext.common.SessionProvider; import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.organization.User; import org.exoplatform.services.organization.UserEventListener; import org.exoplatform.services.security.IdentityConstants; import javax.jcr.*; import java.security.AccessControlException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by IntelliJ IDEA. * User: kmenzli * Date: 28/12/11 * Time: 16:14 * To change this template use File | Settings | File Templates. */ public class UserDriveExtListener extends UserEventListener { private static final Log LOG = ExoLogger.getLogger(UserDriveExtListener.class); private static final String SYMLINK_NAME = "Public"; private static final String SYMLIN_TYPE = "exo:symlink"; private static final String PUPLIC_DRIVE_EXT = "/Public"; private static final String PRIVATE_DRIVE_EXT = "/Private"; private final static String WORKSPACE = "exo:workspace"; private final static String UUID = "exo:uuid"; private final static String PRIMARY_TYPE = "exo:primaryType"; /** RepositoryService used to get current Repository */ private final RepositoryService repositoryService_; /** LinkManager Service to create jcr symlink **/ private final LinkManager linkManager_; /** NodeHierarchyCreator Service : used to get complet path to a given user Folder */ private NodeHierarchyCreator nodeHierarchyCreator_ ; public UserDriveExtListener (RepositoryService repositoryService, LinkManager linkManager, NodeHierarchyCreator nodeHierarchyCreator) throws Exception { this.repositoryService_ = repositoryService; this.linkManager_ = linkManager; nodeHierarchyCreator_ = nodeHierarchyCreator ; } public void postSave(User user, boolean isNew) throws Exception { if (isNew) { createLink(user.getUserName()); } } private void createLink(String userName) throws Exception { SessionProvider sessionProvider = SessionProvider.createSystemProvider(); Session session = getSession(sessionProvider); /** path to private user drive*/ String privatePathUserFolder = ""; /** path to public user drive*/ String publicPathUserFolder = ""; try { Node userNode = nodeHierarchyCreator_.getUserNode(sessionProvider,userName); privatePathUserFolder = userNode.getPath().concat(PRIVATE_DRIVE_EXT); publicPathUserFolder = userNode.getPath().concat(PUPLIC_DRIVE_EXT); Node symLinkParent = (Node) session.getItem(privatePathUserFolder); Node targetNode = (Node) session.getItem(publicPathUserFolder); Node linkNode = null; /** linkNode = linkManager_.createLink(symLinkParent,SYMLIN_TYPE,targetNode,SYMLINK_NAME); */ linkNode = createLink(symLinkParent,SYMLIN_TYPE,targetNode,SYMLINK_NAME); ((ExtendedNode)linkNode).setPermission(IdentityConstants.ANY, new String[]{PermissionType.READ}); linkNode.save(); } catch (Exception e) { LOG.error("An error occurs while processing the creation of Public Symlink " ,e); } finally { if (session != null) { session.logout(); } if (sessionProvider != null) { sessionProvider.close(); } } } private Session getSession(SessionProvider sessionProvider) throws RepositoryException { ManageableRepository repository = repositoryService_.getCurrentRepository(); return sessionProvider.getSession(repository.getConfiguration().getDefaultWorkspaceName(), repository); } private Node createLink(Node parent, String linkType, Node target, String linkName) throws RepositoryException { if (!target.isNodeType(SYMLIN_TYPE)) { if (target.canAddMixin("mix:referenceable")) { target.addMixin("mix:referenceable"); target.getSession().save(); } if (linkType == null || linkType.trim().length() == 0) linkType = SYMLIN_TYPE; if (linkName == null || linkName.trim().length() == 0) linkName = target.getName(); Node linkNode = parent.addNode(linkName, linkType); try { updateAccessPermissionToLink(linkNode, target); } catch(Exception e) { if (LOG.isErrorEnabled()) { LOG.error("CAN NOT UPDATE ACCESS PERMISSIONS FROM TARGET NODE TO LINK NODE", e); } } linkNode.setProperty(WORKSPACE, target.getSession().getWorkspace().getName()); linkNode.setProperty(PRIMARY_TYPE, target.getPrimaryNodeType().getName()); linkNode.setProperty(UUID, target.getUUID()); linkNode.getSession().save(); return linkNode; } return null; } private boolean canChangePermission(Node node) throws RepositoryException { try { ((ExtendedNode)node).checkPermission(PermissionType.CHANGE_PERMISSION); return true; } catch(AccessControlException e) { return false; } } private void updateAccessPermissionToLink(Node linkNode, Node targetNode) throws Exception { if(canChangePermission(linkNode)) { if(linkNode.canAddMixin("exo:privilegeable")) { linkNode.addMixin("exo:privilegeable"); ((ExtendedNode)linkNode).setPermission(getNodeOwner(linkNode),PermissionType.ALL); } removeCurrentIdentites(linkNode); Map<String, String[]> perMap = new HashMap<String, String[]>(); List<String> permsList = new ArrayList<String>(); List<String> idList = new ArrayList<String>(); for(AccessControlEntry accessEntry : ((ExtendedNode)targetNode).getACL().getPermissionEntries()) { if(!idList.contains(accessEntry.getIdentity())) { idList.add(accessEntry.getIdentity()); permsList = ((ExtendedNode)targetNode).getACL().getPermissions(accessEntry.getIdentity()); perMap.put(accessEntry.getIdentity(), permsList.toArray(new String[permsList.size()])); } } ((ExtendedNode)linkNode).setPermissions(perMap); } } private String getNodeOwner(Node node) throws ValueFormatException, PathNotFoundException, RepositoryException { if(node.hasProperty("exo:owner")) { return node.getProperty("exo:owner").getString(); } return IdentityConstants.SYSTEM; } private void removeCurrentIdentites(Node linkNode) throws AccessControlException, RepositoryException { String currentUser = linkNode.getSession().getUserID(); if (currentUser != null) ((ExtendedNode)linkNode).setPermission(currentUser, PermissionType.ALL); for(AccessControlEntry accessEntry : ((ExtendedNode)linkNode).getACL().getPermissionEntries()) { if(canRemovePermission(linkNode, accessEntry.getIdentity()) && ((ExtendedNode)linkNode).getACL().getPermissions(accessEntry.getIdentity()).size() > 0 && !accessEntry.getIdentity().equals(currentUser)) { ((ExtendedNode) linkNode).removePermission(accessEntry.getIdentity()); } } } private boolean canRemovePermission(Node node, String identity) throws ValueFormatException, PathNotFoundException, RepositoryException { String owner = getNodeOwner(node); if(identity.equals(IdentityConstants.SYSTEM)) return false; if(owner != null && owner.equals(identity)) return false; return true; } }