2018-06-29 16:59:24 +02:00
|
|
|
package org.gcube.data.access.storagehub.services;
|
|
|
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import javax.enterprise.context.RequestScoped;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import javax.jcr.Node;
|
2018-10-25 16:33:23 +02:00
|
|
|
import javax.jcr.RepositoryException;
|
2018-06-29 16:59:24 +02:00
|
|
|
import javax.jcr.Session;
|
2019-03-27 15:51:27 +01:00
|
|
|
import javax.jcr.lock.LockException;
|
2018-06-29 16:59:24 +02:00
|
|
|
import javax.jcr.security.AccessControlManager;
|
|
|
|
import javax.jcr.security.Privilege;
|
|
|
|
import javax.servlet.ServletContext;
|
|
|
|
import javax.ws.rs.Consumes;
|
|
|
|
import javax.ws.rs.PUT;
|
|
|
|
import javax.ws.rs.Path;
|
|
|
|
import javax.ws.rs.PathParam;
|
|
|
|
import javax.ws.rs.Produces;
|
|
|
|
import javax.ws.rs.core.Context;
|
|
|
|
import javax.ws.rs.core.MediaType;
|
2019-03-26 17:09:26 +01:00
|
|
|
import javax.ws.rs.core.Response;
|
2018-06-29 16:59:24 +02:00
|
|
|
|
|
|
|
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
|
|
|
|
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
|
|
|
|
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse;
|
|
|
|
import org.gcube.common.storagehub.model.Excludes;
|
2018-06-29 16:59:24 +02:00
|
|
|
import org.gcube.common.storagehub.model.NodeConstants;
|
|
|
|
import org.gcube.common.storagehub.model.acls.AccessType;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
|
|
|
|
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
|
|
|
|
import org.gcube.common.storagehub.model.exceptions.InvalidItemException;
|
2019-03-27 15:51:27 +01:00
|
|
|
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
2018-06-29 16:59:24 +02:00
|
|
|
import org.gcube.common.storagehub.model.items.FolderItem;
|
|
|
|
import org.gcube.common.storagehub.model.items.Item;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.common.storagehub.model.items.SharedFolder;
|
|
|
|
import org.gcube.common.storagehub.model.types.NodeProperty;
|
2018-06-29 16:59:24 +02:00
|
|
|
import org.gcube.common.storagehub.model.types.PrimaryNodeType;
|
|
|
|
import org.gcube.data.access.storagehub.AuthorizationChecker;
|
|
|
|
import org.gcube.data.access.storagehub.Constants;
|
|
|
|
import org.gcube.data.access.storagehub.Utils;
|
|
|
|
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
|
2018-07-03 12:15:35 +02:00
|
|
|
import org.gcube.data.access.storagehub.handlers.CredentialHandler;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.data.access.storagehub.handlers.Item2NodeConverter;
|
|
|
|
import org.gcube.data.access.storagehub.handlers.Node2ItemConverter;
|
2018-12-17 14:55:43 +01:00
|
|
|
import org.gcube.data.access.storagehub.handlers.UnshareHandler;
|
2018-07-05 16:26:08 +02:00
|
|
|
import org.gcube.smartgears.utils.InnerMethodName;
|
2018-06-29 16:59:24 +02:00
|
|
|
import org.glassfish.jersey.media.multipart.FormDataParam;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
@Path("items")
|
|
|
|
public class ItemSharing {
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(ItemSharing.class);
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
RepositoryInitializer repository;
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
AccountingHandler accountingHandler;
|
|
|
|
|
|
|
|
@RequestScoped
|
|
|
|
@PathParam("id")
|
|
|
|
String id;
|
|
|
|
|
|
|
|
@Context
|
|
|
|
ServletContext context;
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
AuthorizationChecker authChecker;
|
|
|
|
|
|
|
|
@Inject
|
2018-12-17 14:55:43 +01:00
|
|
|
UnshareHandler unshareHandler;
|
2018-10-25 16:33:23 +02:00
|
|
|
|
|
|
|
@Inject Node2ItemConverter node2Item;
|
|
|
|
@Inject Item2NodeConverter item2Node;
|
|
|
|
|
2018-06-29 16:59:24 +02:00
|
|
|
@PUT
|
|
|
|
@Path("{id}/share")
|
|
|
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
|
|
|
public String share(@FormDataParam("users") Set<String> users, @FormDataParam("defaultAccessType") AccessType accessType){
|
2018-10-25 16:33:23 +02:00
|
|
|
InnerMethodName.instance.set("shareFolder");
|
2018-06-29 16:59:24 +02:00
|
|
|
Session ses = null;
|
2018-10-25 16:33:23 +02:00
|
|
|
String toReturn = null;
|
2018-06-29 16:59:24 +02:00
|
|
|
try{
|
|
|
|
String login = AuthorizationProvider.instance.get().getClient().getId();
|
2018-07-03 12:15:35 +02:00
|
|
|
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
|
2018-06-29 16:59:24 +02:00
|
|
|
authChecker.checkWriteAuthorizationControl(ses, id, false);
|
|
|
|
|
2018-12-19 19:07:05 +01:00
|
|
|
Item item = node2Item.getItem(ses.getNodeByIdentifier(id), Excludes.ALL);
|
2018-06-29 16:59:24 +02:00
|
|
|
|
|
|
|
if (accessType==null)
|
|
|
|
accessType = AccessType.READ_ONLY;
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
if (users==null || users.isEmpty())
|
|
|
|
throw new InvalidCallParameters("users is empty");
|
|
|
|
|
|
|
|
Node nodeToShare = ses.getNodeByIdentifier(id);
|
2019-03-27 15:51:27 +01:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
boolean alreadyShared = false;
|
2019-03-27 15:51:27 +01:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
Node sharedFolderNode;
|
|
|
|
if (!node2Item.checkNodeType(nodeToShare, SharedFolder.class))
|
|
|
|
sharedFolderNode= shareFolder(nodeToShare, ses);
|
|
|
|
else {
|
|
|
|
sharedFolderNode = nodeToShare;
|
|
|
|
alreadyShared = true;
|
|
|
|
}
|
2018-06-29 16:59:24 +02:00
|
|
|
ses.save();
|
|
|
|
|
2019-03-27 15:51:27 +01:00
|
|
|
try {
|
|
|
|
ses.getWorkspace().getLockManager().lock(sharedFolderNode.getPath(), true, true, 0,login);
|
|
|
|
}catch (LockException e) {
|
|
|
|
throw new ItemLockedException(e);
|
|
|
|
}
|
2018-06-29 16:59:24 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
AccessControlManager acm = ses.getAccessControlManager();
|
|
|
|
JackrabbitAccessControlList acls = AccessControlUtils.getAccessControlList(acm, sharedFolderNode.getPath());
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
if (!alreadyShared) {
|
|
|
|
Privilege[] adminPrivileges = new Privilege[] { acm.privilegeFromName(AccessType.ADMINISTRATOR.getValue()) };
|
2018-12-19 19:07:05 +01:00
|
|
|
addUserToSharing(sharedFolderNode, ses, login, item, adminPrivileges, acls);
|
2018-10-25 16:33:23 +02:00
|
|
|
users.remove(login);
|
|
|
|
}
|
2018-06-29 16:59:24 +02:00
|
|
|
|
|
|
|
Privilege[] userPrivileges = new Privilege[] { acm.privilegeFromName(accessType.getValue()) };
|
2018-10-25 16:33:23 +02:00
|
|
|
for (String user : users)
|
2018-06-29 16:59:24 +02:00
|
|
|
try {
|
2018-12-19 19:07:05 +01:00
|
|
|
addUserToSharing(sharedFolderNode, ses, user, null, userPrivileges, acls);
|
2018-10-25 16:33:23 +02:00
|
|
|
}catch(Exception e){
|
|
|
|
log.warn("error adding user {} to sharing of folder {}", user, sharedFolderNode.getName());
|
2018-06-29 16:59:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
acm.setPolicy(sharedFolderNode.getPath(), acls);
|
|
|
|
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
accountingHandler.createShareFolder(sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString(), users, ses, sharedFolderNode, false);
|
2018-06-29 16:59:24 +02:00
|
|
|
|
|
|
|
ses.save();
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
toReturn = sharedFolderNode.getIdentifier();
|
2018-06-29 16:59:24 +02:00
|
|
|
} finally {
|
2019-04-16 18:31:31 +02:00
|
|
|
if (!ses.hasPendingChanges())
|
|
|
|
ses.getWorkspace().getLockManager().unlock(sharedFolderNode.getPath());
|
2018-06-29 16:59:24 +02:00
|
|
|
}
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
}catch(RepositoryException re){
|
|
|
|
log.error("jcr sharing", re);
|
2019-04-16 18:31:31 +02:00
|
|
|
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error sharing folder", re));
|
2018-10-25 16:33:23 +02:00
|
|
|
}catch(StorageHubException she ){
|
2019-03-26 17:09:26 +01:00
|
|
|
log.error(she.getErrorMessage(), she);
|
|
|
|
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
|
2018-10-25 16:33:23 +02:00
|
|
|
}finally{
|
|
|
|
if (ses!=null)
|
|
|
|
ses.logout();
|
|
|
|
}
|
2019-03-27 15:51:27 +01:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
return toReturn;
|
|
|
|
}
|
|
|
|
|
2019-03-27 15:51:27 +01:00
|
|
|
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
private Node shareFolder(Node node, Session ses) throws RepositoryException, BackendGenericError, StorageHubException{
|
|
|
|
String login = AuthorizationProvider.instance.get().getClient().getId();
|
|
|
|
|
2018-12-19 19:07:05 +01:00
|
|
|
if (!node2Item.checkNodeType(node, FolderItem.class) || Utils.hasSharedChildren(node) || !node.getProperty(NodeProperty.PORTAL_LOGIN.toString()).getString().equals(login))
|
2018-10-25 16:33:23 +02:00
|
|
|
throw new InvalidItemException("item with id "+id+" cannot be shared");
|
|
|
|
|
|
|
|
String sharedFolderName = node.getIdentifier();
|
|
|
|
|
|
|
|
String newNodePath = Constants.SHARED_FOLDER_PATH+"/"+sharedFolderName;
|
|
|
|
|
|
|
|
ses.move(node.getPath(),newNodePath);
|
|
|
|
|
|
|
|
Node sharedFolderNode = ses.getNode(newNodePath);
|
|
|
|
|
|
|
|
sharedFolderNode.setPrimaryType(PrimaryNodeType.NT_WORKSPACE_SHARED_FOLDER);
|
|
|
|
|
|
|
|
return sharedFolderNode;
|
|
|
|
}
|
|
|
|
|
2018-12-19 19:07:05 +01:00
|
|
|
private void addUserToSharing(Node sharedFolderNode, Session ses, String user, Item itemToShare, Privilege[] userPrivileges, JackrabbitAccessControlList acls) throws RepositoryException{
|
|
|
|
String userRootWSId;
|
|
|
|
String userPath;
|
|
|
|
if (itemToShare==null) {
|
|
|
|
String userRootWS = Utils.getWorkspacePath(user).toPath();
|
|
|
|
userRootWSId = ses.getNode(userRootWS).getIdentifier();
|
|
|
|
userPath = String.format("%s%s",userRootWS,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
userPath = itemToShare.getPath();
|
|
|
|
userRootWSId = itemToShare.getParentId();
|
|
|
|
}
|
2019-03-27 15:51:27 +01:00
|
|
|
|
|
|
|
|
2018-12-19 19:07:05 +01:00
|
|
|
log.info("cloning directory to {} ",userPath);
|
2019-03-27 15:51:27 +01:00
|
|
|
|
2018-12-19 19:07:05 +01:00
|
|
|
ses.getWorkspace().clone(ses.getWorkspace().getName(), sharedFolderNode.getPath(), userPath , false);
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
acls.addAccessControlEntry(AccessControlUtils.getPrincipal(ses, user), userPrivileges );
|
|
|
|
Node usersNode =null;
|
|
|
|
if (sharedFolderNode.hasNode(NodeConstants.USERS_NAME))
|
|
|
|
usersNode = sharedFolderNode.getNode(NodeConstants.USERS_NAME);
|
|
|
|
else
|
|
|
|
usersNode = sharedFolderNode.addNode(NodeConstants.USERS_NAME);
|
|
|
|
usersNode.setProperty(user, String.format("%s/%s",userRootWSId,sharedFolderNode.getProperty(NodeProperty.TITLE.toString()).getString()));
|
|
|
|
}
|
2018-06-29 16:59:24 +02:00
|
|
|
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
@PUT
|
|
|
|
@Path("{id}/unshare")
|
|
|
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
|
|
|
public String unshare(@FormDataParam("users") Set<String> users){
|
|
|
|
InnerMethodName.instance.set("unshareFolder");
|
|
|
|
String login = AuthorizationProvider.instance.get().getClient().getId();
|
|
|
|
Session ses = null;
|
|
|
|
String toReturn = null;
|
|
|
|
try {
|
|
|
|
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
|
|
|
|
Node sharedNode = ses.getNodeByIdentifier(id);
|
2018-12-17 14:55:43 +01:00
|
|
|
toReturn = unshareHandler.unshare(ses, users, sharedNode, login);
|
|
|
|
if(toReturn == null ) throw new InvalidItemException("item with id "+id+" cannot be unshared");
|
2018-10-25 16:33:23 +02:00
|
|
|
}catch(RepositoryException re){
|
|
|
|
log.error("jcr unsharing", re);
|
|
|
|
GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error extracting archive", re));
|
|
|
|
}catch(StorageHubException she ){
|
2019-03-26 17:09:26 +01:00
|
|
|
log.error(she.getErrorMessage(), she);
|
|
|
|
GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus()));
|
2018-06-29 16:59:24 +02:00
|
|
|
}finally{
|
2018-10-25 16:33:23 +02:00
|
|
|
|
2018-06-29 16:59:24 +02:00
|
|
|
if (ses!=null)
|
|
|
|
ses.logout();
|
|
|
|
}
|
2018-10-25 16:33:23 +02:00
|
|
|
return toReturn;
|
|
|
|
}
|
2018-06-29 16:59:24 +02:00
|
|
|
|
2019-03-27 15:51:27 +01:00
|
|
|
|
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
|
|
|
|
|
2018-06-29 16:59:24 +02:00
|
|
|
}
|