package org.gcube.data.access.storagehub; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.security.AccessControlEntry; import javax.jcr.security.Privilege; import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils; import org.gcube.common.authorization.library.provider.AuthorizationProvider; import org.gcube.common.authorization.library.provider.ClientInfo; import org.gcube.common.storagehub.model.Excludes; 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.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 * * */ public class AuthorizationChecker { private static Logger log = LoggerFactory.getLogger(AuthorizationChecker.class); @Inject Node2ItemConverter node2Item; @Inject PathUtil pathUtil; String userToCheck; public AuthorizationChecker(){ ClientInfo client = AuthorizationProvider.instance.get().getClient(); this.userToCheck = client.getId(); } public AuthorizationChecker(String userToCheck){ this.userToCheck = userToCheck; } public String getUserToCheck() { return userToCheck; } public void setUserToCheck(String user) { this.userToCheck = user; } public void checkReadAuthorizationControl(Session session, 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.getOldTrashPath(userToCheck).toPath())) return; if (!item.isShared() && item.getOwner()!=null && item.getOwner().equals(userToCheck)) return; if (hasParentPublicFolder(session, item)) 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 JackrabbitAccessControlList accessControlList = AccessControlUtils.getAccessControlList(session, parentShared.getPath()); AccessControlEntry[] entries = accessControlList.getAccessControlEntries(); Authorizable userAuthorizable = ((JackrabbitSession) session).getUserManager().getAuthorizable(userToCheck); for (AccessControlEntry entry: entries) { log.debug("checking access right for {} with compared with {}",userToCheck, entry.getPrincipal()); Authorizable authorizable = ((JackrabbitSession) session).getUserManager().getAuthorizable(entry.getPrincipal()); if (authorizable==null) { log.warn("{} doesn't have a correspondant auhtorizable object, check it ", entry.getPrincipal()); continue; } try { if (!authorizable.isGroup() && entry.getPrincipal().getName().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); } throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+" to read node with id "+id); } private boolean hasParentPublicFolder(Session session, Item item) { 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; } } } private Node retrieveSharedFolderParent(Node node, Session session) throws BackendGenericError, RepositoryException{ if (node2Item.checkNodeType(node, SharedFolder.class)) return node; else return retrieveSharedFolderParent(node.getParent(), session); } //newItem means that a new item will be created and id is the destination directory public void checkWriteAuthorizationControl(Session session, 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.isTrashed()) throw new UserNotAuthorizedException("Trashed item cannot be written");*/ if (item.isShared()) { Node parentSharedNode = retrieveSharedFolderParent(node, session); JackrabbitAccessControlList accessControlList = AccessControlUtils.getAccessControlList(session, parentSharedNode.getPath()); AccessControlEntry[] entries = accessControlList.getAccessControlEntries(); Authorizable UserAuthorizable = ((JackrabbitSession) session).getUserManager().getAuthorizable(userToCheck); //put it in a different method for (AccessControlEntry entry: entries) { Authorizable authorizable = ((JackrabbitSession) session).getUserManager().getAuthorizable(entry.getPrincipal()); if ((!authorizable.isGroup() && entry.getPrincipal().getName().equals(userToCheck)) || (authorizable.isGroup() && ((Group) authorizable).isMember(UserAuthorizable))){ for (Privilege privilege : entry.getPrivileges()){ AccessType access = AccessType.fromValue(privilege.getName()); if (isNewItem && access!=AccessType.READ_ONLY) return; else if (!isNewItem && (access==AccessType.ADMINISTRATOR || access==AccessType.WRITE_ALL || (access==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 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, item, node, isNewItem); } 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"); } public void checkAdministratorControl(Session session, SharedFolder item) throws UserNotAuthorizedException, BackendGenericError, RepositoryException { if (item==null) throw new UserNotAuthorizedException("Insufficent Privileges for user "+userToCheck+": it's not a valid StorageHub node"); Node node = session.getNodeByIdentifier(item.getId()); if (item.isShared()) { Node parentSharedNode = retrieveSharedFolderParent(node, session); JackrabbitAccessControlList accessControlList = AccessControlUtils.getAccessControlList(session, parentSharedNode.getPath()); AccessControlEntry[] entries = accessControlList.getAccessControlEntries(); //put it in a different method SharedFolder parentShared = node2Item.getItem(parentSharedNode, Excludes.EXCLUDE_ACCOUNTING); for (AccessControlEntry entry: entries) { if (entry.getPrincipal().getName().equals(userToCheck) || (parentShared.isVreFolder() && entry.getPrincipal().getName().equals(parentShared.getTitle()))) { for (Privilege privilege : entry.getPrivileges()){ AccessType access = AccessType.fromValue(privilege.getName()); if (access==AccessType.ADMINISTRATOR) return; } //throw new UserNotAuthorizedException("The user "+login+" is not an administrator of node with id "+item.getId()); } } } //else should never happen throw new UserNotAuthorizedException("The user "+userToCheck+" is not an administrator of node with id "+item.getId()); } /* private String retrieveOwner(Node node) { Node nodeOwner; //get Owner try{ return node.getProperty(NodeProperty.PORTAL_LOGIN.toString()).getString(); }catch (Exception e) { try { nodeOwner = node.getNode(NodeProperty.OWNER.toString()); return nodeOwner.getProperty(NodeProperty.PORTAL_LOGIN.toString()).getString(); // this.userId = nodeOwner.getProperty(USER_ID).getString(); // this.portalLogin = nodeOwner.getProperty(PORTAL_LOGIN).getString(); // node.getSession().save(); } catch (Exception e1) { throw new RuntimeException(e1); } } } */ }