package org.gcube.data.access.storagehub; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.jackrabbit.api.JackrabbitSession; 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.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.acls.ACL; import org.gcube.common.storagehub.model.acls.AccessType; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; 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.items.TrashItem; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; import org.gcube.data.access.storagehub.services.interfaces.ACLManagerInterface; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * * the caller must be authorized, so i'm not passing the login also if it works on behalf of an user * * */ @Singleton public class AuthorizationChecker { private static Logger log = LoggerFactory.getLogger(AuthorizationChecker.class); @Inject Node2ItemConverter node2Item; @Inject PathUtil pathUtil; @Inject ACLManagerInterface aclManager; public void checkReadAuthorizationControl(Session session, String userToCheck, String id) throws UserNotAuthorizedException , BackendGenericError, RepositoryException{ Node node = session.getNodeByIdentifier(id); Item item = node2Item.getItem(node, Excludes.ALL); if (item==null) throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+" to read node with id "+id+": it's not a valid StorageHub node"); //checking if the item is in the owner trash folder if(item instanceof TrashItem && item.getParentPath().equals(pathUtil.getTrashPath(userToCheck, session).toPath())) return; if (!item.isShared() && item.getOwner()!=null && item.getOwner().equals(userToCheck)) return; if (hasParentPublicFolder(session, item)) return; //TODO: remove when messages will be passed to a new system String parentPath = item.getParentPath(); if (parentPath.endsWith("hl:attachments") && (parentPath.contains("/OutBox/") || parentPath.contains("/InBox/"))) { return ; } if (item.isShared()) { //SharedFolder parentShared = node2Item.getItem(retrieveSharedFolderParent(node, session), Excludes.EXCLUDE_ACCOUNTING); //if (parentShared.getUsers().getMap().keySet().contains(userToCheck)) return; //CHECKING ACL FOR VREFOLDER AND SHARED FOLDER List acls = aclManager.get(item, session); UserManager userManager = ((JackrabbitSession) session).getUserManager(); Authorizable userAuthorizable = userManager.getAuthorizable(userToCheck); for (ACL entry: acls) { log.debug("checking access right for {} with compared with {}",userToCheck, entry.getPricipal()); Authorizable authorizable = userManager.getAuthorizable(entry.getPricipal()); if (authorizable==null) { log.warn("{} doesn't have a correspondant auhtorizable object, check it ", entry.getPricipal()); continue; } try { if (!authorizable.isGroup() && entry.getPricipal().equals(userToCheck)) return; if (authorizable.isGroup() && ((Group) authorizable).isMember(userAuthorizable)) return; }catch (Throwable e) { log.warn("someting went wrong checking authorizations",e); } } } throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+" to read node with id "+id); } private boolean hasParentPublicFolder(Session session, Item item) { if(item==null || item.getParentPath()==null) return false; if (item.getParentPath().replaceAll("/Home/[^/]*/"+Constants.WORKSPACE_ROOT_FOLDER_NAME,"").isEmpty() || item.getParentPath().replaceAll(Constants.SHARED_FOLDER_PATH, "").isEmpty()) { if (item instanceof FolderItem) return ((FolderItem) item).isPublicItem(); else return false; } else { if (item instanceof FolderItem) try { return ((FolderItem) item).isPublicItem() || hasParentPublicFolder(session, node2Item.getItem(item.getParentId(), session, Excludes.ALL)); }catch (Throwable e) { log.warn("error checking public parents",e); return false; } else try { return hasParentPublicFolder(session, node2Item.getItem(item.getParentId(), session, Excludes.ALL)); }catch (Throwable e) { log.warn("error checking public parents",e); return false; } } } //newItem means that a new item will be created and id is the destination directory public void checkWriteAuthorizationControl(Session session, String userToCheck, Item item, Node node, boolean isNewItem) throws UserNotAuthorizedException, BackendGenericError, RepositoryException { if (item==null) throw new UserNotAuthorizedException("Not valid StorageHub node"); if (Constants.WRITE_PROTECTED_FOLDER.contains(item.getName()) || Constants.WRITE_PROTECTED_FOLDER.contains(item.getTitle())) throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+" to write into node with id "+item.getId()+": it's a protected folder"); if (item.isShared()) { //CHECKING ACL FOR VREFOLDER AND SHARED FOLDER List acls = aclManager.get(item, session); UserManager userManager = ((JackrabbitSession) session).getUserManager(); Authorizable UserAuthorizable = userManager.getAuthorizable(userToCheck); //put it in a different method for (ACL entry: acls) { Authorizable authorizable = userManager.getAuthorizable(entry.getPricipal()); if ((!authorizable.isGroup() && entry.getPricipal().equals(userToCheck)) || (authorizable.isGroup() && ((Group) authorizable).isMember(UserAuthorizable))){ for (AccessType privilege : entry.getAccessTypes()){ if (isNewItem && privilege!=AccessType.READ_ONLY) return; else if (!isNewItem && (privilege==AccessType.ADMINISTRATOR || privilege==AccessType.WRITE_ALL || (privilege==AccessType.WRITE_OWNER && item.getOwner().equals(userToCheck)))) return; } } } } else if(item.getOwner().equals(userToCheck)) return; throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+" to write into node with id "+item.getId()); } //newItem means that a new item will be created and id is the destination directory public void checkWriteAuthorizationControl(Session session, String userToCheck , String id, boolean isNewItem) throws UserNotAuthorizedException, BackendGenericError, RepositoryException { //in case of newItem the id is the parent otherwise the old node to replace Node node = session.getNodeByIdentifier(id); Item item = node2Item.getItem(node, Excludes.ALL); checkWriteAuthorizationControl(session, userToCheck, item, node, isNewItem); } /** * * checks if item with {id} can be moved * */ public void checkMoveOpsForProtectedFolders(Session session, String id) throws InvalidCallParameters, BackendGenericError, RepositoryException { Node node = session.getNodeByIdentifier(id); Item item = node2Item.getItem(node, Excludes.ALL); if (Constants.PROTECTED_FOLDER.contains(item.getName()) || Constants.PROTECTED_FOLDER.contains(item.getTitle())) throw new InvalidCallParameters("protected folder cannot be moved or deleted"); } /** * * checks if {userToCheck} is an admin for {item} * */ public void checkAdministratorControl(Session session, String userToCheck, SharedFolder item) throws UserNotAuthorizedException, BackendGenericError, RepositoryException { if (item==null) throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+": it's not a valid StorageHub node"); if (item.isShared()) { List acls = aclManager.get(item, session); for (ACL entry: acls) { if (entry.getPricipal().equals(userToCheck)) { for (AccessType privilege : entry.getAccessTypes()){ if (privilege==AccessType.ADMINISTRATOR) return; } } } } throw new UserNotAuthorizedException("The user "+userToCheck+" is not an administrator of node with id "+item.getId()); } }