storagehub/src/main/java/org/gcube/data/access/storagehub/handlers/UnshareHandler.java

347 lines
12 KiB
Java

package org.gcube.data.access.storagehub.handlers;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlManager;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.gcube.common.storagehub.model.Excludes;
import org.gcube.common.storagehub.model.NodeConstants;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.PathUtil;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class UnshareHandler {
private static final Logger log = LoggerFactory.getLogger(UnshareHandler.class);
@Inject
AccountingHandler accountingHandler;
@Inject
Node2ItemConverter node2Item;
@Inject
AuthorizationChecker authChecker;
@Inject
PathUtil pathUtil;
@Inject
Item2NodeConverter item2Node;
public String unshare(Session ses, Set<String> users, Node sharedNode, String login) throws RepositoryException, StorageHubException{
return _unshare(ses, users, sharedNode, login, true);
}
public String unshareForRemoval(Session ses, Set<String> users, Node sharedNode, String login) throws RepositoryException, StorageHubException{
return _unshare(ses, users, sharedNode, login, false);
}
private String _unshare(Session ses, Set<String> users, Node sharedNode, String login, boolean withCopyOnUnshare) throws RepositoryException, StorageHubException{
Item item = node2Item.getItem(sharedNode, Excludes.ALL);
if (!(item instanceof FolderItem) || !((FolderItem) item).isShared() || ((SharedFolder) item).isVreFolder()) {
log.warn("this item type cannot be unshared {}",item.getClass().getSimpleName());
return null;
}
SharedFolder sharedItem =(SharedFolder) item;
Set<String> usersInSharedFolder = new HashSet<>(sharedItem.getUsers().getMap().keySet());
usersInSharedFolder.removeAll(users);
if (users==null || users.size()==0)
return unshareAll(login, ses, sharedItem, withCopyOnUnshare);
if (usersInSharedFolder.size()<=1) {
if (users.size()==1 && users.contains(login))
return unshareAll(sharedItem.getOwner(), ses , sharedItem, withCopyOnUnshare);
else return unshareAll(login, ses, sharedItem, withCopyOnUnshare);
}
try {
ses.getWorkspace().getLockManager().lock(sharedNode.getPath(), true, true, 0,login);
}catch (LockException e) {
throw new ItemLockedException(e);
}
try {
if (users.size()==1 && users.contains(login))
return unshareCaller(login, ses, sharedItem);
else return unsharePartial(users, login, ses, sharedItem);
}finally {
ses.getWorkspace().getLockManager().unlock(sharedNode.getPath());
}
}
private String unshareAll(String login, Session ses, SharedFolder item, boolean withCopyCreation) throws StorageHubException, BackendGenericError, RepositoryException{
log.info("unshare all called");
if (!login.equals(item.getOwner()))
throw new UserNotAuthorizedException("user "+login+" not authorized to unshare all");
Node sharedItemNode = ses.getNodeByIdentifier(item.getId());
try {
ses.getWorkspace().getLockManager().lock(sharedItemNode.getPath(), true, true, 0,login);
}catch (LockException e) {
throw new ItemLockedException(e);
}
String unsharedNodeIdentifier =null;
try {
log.debug("user list is empty, I'm going to remove also the shared dir");
if (withCopyCreation) {
Node sharedOwnerNode = null;
NodeIterator it = sharedItemNode.getSharedSet();
while(it.hasNext()) {
Node node = it.nextNode();
log.info("[UNSHARE] checking node {} starts with {} ",node.getPath(),pathUtil.getHome(login).toPath());
if (node.getPath().startsWith(pathUtil.getHome(login).toPath())) {
sharedOwnerNode =node;
break;
}
}
Node shareParent = sharedOwnerNode.getParent();
sharedOwnerNode.removeShare();
Node unsharedNode = createUnsharedFolder(ses, shareParent , item.getTitle() , item.getDescription(), login);
List<Item> itemsToCopy = Utils.getItemList(sharedItemNode, Excludes.ALL, null, true, null);
for (Item itemCopy: itemsToCopy) {
Node itemToCopyNode = ses.getNodeByIdentifier(itemCopy.getId());
log.debug("copying {} to {}", itemToCopyNode.getPath(), unsharedNode.getPath());
ses.move(itemToCopyNode.getPath(), String.format("%s/%s",unsharedNode.getPath(), itemToCopyNode.getName()));
}
unsharedNode.getNode(NodeProperty.ACCOUNTING.toString()).remove();
ses.move(sharedItemNode.getNode(NodeProperty.ACCOUNTING.toString()).getPath(), String.format("%s/%s",unsharedNode.getPath(), NodeProperty.ACCOUNTING.toString()));
//set owner of all the unshared items to the caller
item2Node.updateOwnerOnSubTree(unsharedNode, login);
accountingHandler.createUnshareFolder(sharedItemNode.getProperty(NodeProperty.TITLE.toString()).getString(), ses, "ALL", unsharedNode, false);
unsharedNodeIdentifier = unsharedNode.getIdentifier();
log.info("[UNSHARE] unshared node id {}",unsharedNodeIdentifier);
ses.save();
}
log.debug("all the users have been removed, the folder is totally unshared");
}catch(Throwable t) {
log.error("erro unsharing all",t);
throw t;
}finally {
ses.getWorkspace().getLockManager().unlock(sharedItemNode.getPath());
}
sharedItemNode.removeSharedSet();
ses.save();
return unsharedNodeIdentifier;
}
private String unshareCaller(String login, Session ses, SharedFolder item) throws StorageHubException, RepositoryException{
log.info("unshare caller");
if (login.equals(item.getOwner()))
throw new InvalidCallParameters("the caller is the owner, the folder cannot be unshared");
Node sharedFolderNode =ses.getNodeByIdentifier(item.getId());
if (item.getUsers().getMap().get(login)!=null) {
Node usersNode = sharedFolderNode.getNode(NodeConstants.USERS_NAME);
usersNode.remove();
Node newUsersNode = sharedFolderNode.addNode(NodeConstants.USERS_NAME);
item.getUsers().getMap().entrySet().stream().filter(entry -> !entry.getKey().equals(login)).forEach(entry-> {try {
newUsersNode.setProperty(entry.getKey(), (String)entry.getValue());
} catch (Exception e) {
log.error("error adding property to shared node users node under {}",item.getId());
}});
}
Node shareNode = getUserSharingNode(login, ses, item);
String parentId = shareNode.getParent().getIdentifier();
//not returning an error to correct all the old ACL
if (shareNode != null)
shareNode.removeShare();
AccessControlManager acm = ses.getAccessControlManager();
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, sharedFolderNode.getPath());
AccessControlEntry entryToDelete= null;
for (AccessControlEntry ace :acls.getAccessControlEntries()) {
if (ace.getPrincipal().getName().equals(login)) {
entryToDelete = ace;
break;
}
}
if (entryToDelete!=null)
acls.removeAccessControlEntry(entryToDelete);
acm.setPolicy(sharedFolderNode.getPath(), acls);
log.debug("removed Access control entry for user {}",login);
accountingHandler.createUnshareFolder(item.getTitle(), ses, login, sharedFolderNode, false);
ses.save();
return parentId;
}
private String unsharePartial(Set<String> usersToUnshare, String login, Session ses, SharedFolder item) throws StorageHubException, RepositoryException {
log.info("unshare partial");
authChecker.checkAdministratorControl(ses, login, (SharedFolder)item);
if (usersToUnshare.contains(item.getOwner()))
throw new UserNotAuthorizedException("user "+login+" not authorized to unshare owner");
Node sharedFolderNode =ses.getNodeByIdentifier(item.getId());
AccessControlManager acm = ses.getAccessControlManager();
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, sharedFolderNode.getPath());
for (String user : usersToUnshare) {
Node userShareNode = getUserSharingNode(user, ses, item);
//not returning an error to correct all the old ACL
if (userShareNode != null)
userShareNode.removeShare();
AccessControlEntry entryToDelete= null;
for (AccessControlEntry ace :acls.getAccessControlEntries()) {
if (ace.getPrincipal().getName().equals(user)) {
entryToDelete = ace;
break;
}
}
if (entryToDelete!=null)
acls.removeAccessControlEntry(entryToDelete);
log.debug("removed Access control entry for user {}",user);
}
Node sharedItemNode = ses.getNodeByIdentifier(item.getId());
Node usersNode = sharedItemNode.getNode(NodeConstants.USERS_NAME);
usersNode.remove();
Node newUsersNode = sharedItemNode.addNode(NodeConstants.USERS_NAME);
item.getUsers().getMap().entrySet().stream().filter(entry -> !usersToUnshare.contains(entry.getKey())).forEach(entry-> {try {
newUsersNode.setProperty(entry.getKey(), (String)entry.getValue());
} catch (Exception e) {
log.error("error adding property to shared node users node under "+item.getId());
}});
acm.setPolicy(sharedFolderNode.getPath(), acls);
for (String user: usersToUnshare) {
accountingHandler.createUnshareFolder(sharedItemNode.getProperty(NodeProperty.TITLE.toString()).getString(), ses, user, sharedItemNode, false);
}
ses.save();
return item.getId();
}
private Node getUserSharingNode(String user, Session ses, SharedFolder item) throws RepositoryException {
Node shareNode = null;
try {
String userDirPath = (String)item.getUsers().getMap().get(user);
if (userDirPath==null) return null;
String[] splitString = userDirPath.split("/");
String parentDirectoryId = splitString[0];
String directoryName = splitString[1];
Node parentNode = null;
parentNode = ses.getNodeByIdentifier(parentDirectoryId);
shareNode = ses.getNode(String.format("%s/%s",parentNode.getPath(), directoryName));
}catch (Throwable e) {
log.warn("users map is not containing a valid value");
}
Node sharedFolderNode = ses.getNodeByIdentifier(item.getId());
if (shareNode==null) {
NodeIterator it = sharedFolderNode.getSharedSet();
while(it.hasNext()) {
Node node = it.nextNode();
if (node.getPath().startsWith(pathUtil.getHome(user).toPath())) {
shareNode =node;
break;
}
}
}
return shareNode;
}
private Node createUnsharedFolder(Session ses, Node destinationNode, String name, String description, String login) {
FolderItem item = new FolderItem();
Calendar now = Calendar.getInstance();
item.setName(name);
item.setTitle(name);
item.setDescription(description);
//item.setCreationTime(now);
item.setHidden(false);
item.setLastAction(ItemAction.CREATED);
item.setLastModificationTime(now);
item.setLastModifiedBy(login);
item.setOwner(login);
//to inherit hidden property
//item.setHidden(destinationItem.isHidden());
Node newNode = item2Node.getNode(destinationNode, item);
return newNode;
}
}