package org.gcube.data.access.storagehub.services; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.function.Predicate; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.jcr.query.QueryResult; import javax.servlet.ServletContext; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; 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; import javax.ws.rs.core.Response; import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.Query; import org.apache.jackrabbit.api.security.user.QueryBuilder; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.core.security.principal.PrincipalImpl; import org.apache.poi.hpsf.Array; import org.gcube.common.authorization.control.annotations.AuthorizationControl; import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse; import org.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.SharedFolder; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.AuthorizationChecker; import org.gcube.data.access.storagehub.Constants; import org.gcube.data.access.storagehub.StorageHubAppllicationManager; import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.exception.MyAuthException; import org.gcube.data.access.storagehub.handlers.CredentialHandler; import org.gcube.data.access.storagehub.handlers.TrashHandler; import org.gcube.data.access.storagehub.handlers.UnshareHandler; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.utils.InnerMethodName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("users") @ManagedBy(StorageHubAppllicationManager.class) public class UserManager { private static final String INFRASTRUCTURE_MANAGER_ROLE = "Infrastructure-Manager"; @Context ServletContext context; private static final Logger log = LoggerFactory.getLogger(UserManager.class); RepositoryInitializer repository = StorageHubAppllicationManager.repository; @Inject UnshareHandler unshareHandler; @Inject TrashHandler trashHandler; @Inject AuthorizationChecker authChecker; @GET @Path("") @Produces(MediaType.APPLICATION_JSON) public List getUsers(){ InnerMethodName.instance.set("getUsers"); JackrabbitSession session = null; List users = null; try { session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Iterator result = session.getUserManager().findAuthorizables(new Query() { @Override public void build(QueryBuilder builder) { builder.setSelector(User.class); } }); Set usersSet= new HashSet<>(); String adminUser = context.getInitParameter(Constants.ADMIN_PARAM_NAME); while (result.hasNext()) { Authorizable user = result.next(); log.debug("user {} found",user.getPrincipal().getName()); if (user.getPrincipal().getName().equals(adminUser)) continue; usersSet.add(user.getPrincipal().getName()); } users = new ArrayList<>(usersSet); Collections.sort(users); }catch(Exception e) { log.error("jcr error getting users", e); GXOutboundErrorResponse.throwException(new BackendGenericError(e)); } finally { if (session!=null) session.logout(); } return users; } @GET @Path("{user}") public String getUser(@PathParam("user") String user){ InnerMethodName.instance.set("getUser"); JackrabbitSession session = null; try { session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager(); Authorizable authorizable = usrManager.getAuthorizable(user); if (authorizable != null && !authorizable.isGroup()) return authorizable.getPrincipal().getName(); log.debug("user {} not found", user); }catch(Exception e) { log.error("jcr error getting user", e); GXOutboundErrorResponse.throwException(new BackendGenericError(e)); } finally { if (session!=null) session.logout(); } GXOutboundErrorResponse.throwException(new IdNotFoundException(user)); return null; } @POST @Path("") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class) public String createUser(@FormParam("user") String user, @FormParam("password") String password){ InnerMethodName.instance.set("createUser"); JackrabbitSession session = null; String userId = null; try { session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager(); User createdUser = usrManager.createUser(user, password); userId = createdUser.getID(); Node homeNode = session.getNode("/Home"); Node userHome = homeNode.addNode(user, "nthl:home"); //creating workspace folder Node workspaceFolder = Utils.createFolderInternally(session, userHome, Constants.WORKSPACE_ROOT_FOLDER_NAME, "workspace of "+user, false, user, null); //creating thrash folder Utils.createFolderInternally(session, workspaceFolder, Constants.TRASH_ROOT_FOLDER_NAME, "trash of "+user, false, user, null); //creating Vre container folder Utils.createFolderInternally(session, workspaceFolder, Constants.VRE_FOLDER_PARENT_NAME, "special folder container of "+user, false, user, null); session.save(); }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she); GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); }catch(RepositoryException re ){ log.error("jcr error creating item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re)); } finally { if (session!=null) session.logout(); } return userId; } @DELETE @Path("{user}") @AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=MyAuthException.class) public String deleteUser(@PathParam("user") final String user){ InnerMethodName.instance.set("deleteUser"); JackrabbitSession session = null; String userId = null; try { session = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); org.apache.jackrabbit.api.security.user.UserManager usrManager = session.getUserManager(); try { Node sharedFolderNode = session.getNode(Constants.SHARED_FOLDER_PATH); Predicate sharedWithUserChecker = new Predicate() { @Override public boolean test(Node t) { try { authChecker.checkReadAuthorizationControl(t.getSession(), user, t.getIdentifier()); return !t.getProperty(NodeProperty.IS_VRE_FOLDER.toString()).getBoolean() ; } catch (UserNotAuthorizedException | BackendGenericError | RepositoryException e) { return false; } } }; List items = Utils.getItemList(sharedWithUserChecker, sharedFolderNode, Excludes.ALL, null, false, SharedFolder.class); for (SharedFolder item: items) { if (item.isPublicItem() && !item.getUsers().getMap().containsKey(user)) continue; String title = item.getTitle(); log.debug("removing sharing for folder name {} with title {} and path {} ",item.getName(), title, item.getPath()); String owner = item.getOwner(); Set usersToUnshare= owner.equals(user)? Collections.emptySet():Collections.singleton(user); try { unshareHandler.unshare(session, usersToUnshare, session.getNodeByIdentifier(item.getId()), user); }catch (Throwable e) { log.warn("error unsharing folder with title '{}' and id {} ", title, item.getId(), e); } } } catch (Throwable t) { log.warn("error getting folder shared with ", t); } org.gcube.common.storagehub.model.Path homePath = Utils.getHome(user); org.gcube.common.storagehub.model.Path workspacePath = Utils.getWorkspacePath(user); try { Node workspaceNode = session.getNode(workspacePath.toPath()); Node homeNode = session.getNode(homePath.toPath()); List workspaceItems = Utils.getItemList(workspaceNode, Excludes.GET_ONLY_CONTENT, null, true, null); trashHandler.removeOnlyNodesContent(session, workspaceItems); homeNode.remove(); } catch (PathNotFoundException e) { log.warn("{} home dir was already deleted", user); } Authorizable authorizable = usrManager.getAuthorizable(new PrincipalImpl(user)); if (authorizable!=null && !authorizable.isGroup()) { log.info("removing user {}", user); authorizable.remove(); } else log.warn("the user {} was already deleted", user); session.save(); }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she); GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); }catch(RepositoryException re ){ log.error("jcr error creating item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error creating item", re)); } finally { if (session!=null) session.logout(); } return userId; } }