From 8f794709a8511be1ce51a17469fccbcbcdf766df Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 22 Aug 2017 15:55:22 +0200
Subject: [PATCH] user API for updating user privileges

---
 .../mapviewer/api/users/UserController.java   | 18 ++++-
 .../mapviewer/api/users/UserRestImpl.java     | 49 +++++++++++++-
 .../mapviewer/api/users/UserRestImplTest.java | 25 ++++++-
 .../mapviewer/services/impl/UserService.java  | 67 ++++++++++++++++---
 .../services/interfaces/IUserService.java     |  6 +-
 .../mapviewer/bean/ConfigurationBeanTest.java |  4 +-
 6 files changed, 152 insertions(+), 17 deletions(-)

diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
index df347b2f27..b2a15c3e9f 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
@@ -14,13 +14,18 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.ObjectNotFoundException;
+import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.IUserService;
@@ -77,7 +82,18 @@ public class UserController extends BaseController {
 	) throws SecurityException, ObjectNotFoundException {
 		return userRest.getUser(token, login, columns);
 	}
-	
+
+	@RequestMapping(value = "/users/{login}:updatePrivileges", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
+	public Map<String, Object> updatePrivileges(//
+			@RequestBody String body, //
+			@CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+			@PathVariable(value = "login") String login //
+	) throws SecurityException, JsonParseException, JsonMappingException, IOException, QueryException {
+		Map<String, Object> node = parseBody(body);
+		Map<String, Object> data = getData(node, "privileges");
+		return userRest.updatePrivileges(token, login, data);
+	}
+
 	@RequestMapping(value = "/users/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
 	public List<Map<String, Object>> getUsers(//
 			@CookieValue(value = Configuration.AUTH_TOKEN) String token, //
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
index 427f8f0b07..ee5dfd2b19 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
@@ -7,11 +7,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
 import lcsb.mapviewer.api.BaseRestImpl;
 import lcsb.mapviewer.api.ObjectNotFoundException;
+import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.model.user.BasicPrivilege;
 import lcsb.mapviewer.model.user.ObjectPrivilege;
@@ -24,6 +26,7 @@ import lcsb.mapviewer.services.view.AuthenticationToken;
 
 @Transactional(value = "txManager")
 public class UserRestImpl extends BaseRestImpl {
+	Logger logger = Logger.getLogger(UserRestImpl.class);
 
 	@Autowired
 	private ILayoutService layoutService;
@@ -35,13 +38,12 @@ public class UserRestImpl extends BaseRestImpl {
 
 		boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
 
-		if (ownUserData.getLogin().equals(login)) {
-			return prepareUse(ownUserData, columnSet, true);
-		} else if (isAdmin) {
+		if (ownUserData.getLogin().equals(login) || isAdmin) {
 			User user = getUserService().getUserByLogin(login);
 			if (user == null) {
 				throw new ObjectNotFoundException("User doesn't exist");
 			}
+			logger.debug(user.hashCode());
 			return prepareUse(user, columnSet, isAdmin);
 		} else {
 			throw new SecurityException("You cannot access data of the user with given id");
@@ -168,4 +170,45 @@ public class UserRestImpl extends BaseRestImpl {
 		return result;
 	}
 
+	public Map<String, Object> updatePrivileges(String token, String login, Map<String, Object> privilegesData) throws SecurityException, QueryException {
+		if (privilegesData == null) {
+			throw new QueryException("Privileges not defined");
+		}
+		logger.debug(privilegesData);
+		try {
+			AuthenticationToken authenticationToken = getUserService().getToken(token);
+			User modifiedUser = getUserService().getUserByLogin(login);
+			logger.debug(modifiedUser.hashCode());
+
+			for (String key : privilegesData.keySet()) {
+				Object value = privilegesData.get(key);
+
+				PrivilegeType type = PrivilegeType.valueOf(key);
+				Integer objectId = null;
+				Object privilegeToSet = null;
+				if (type.getPrivilegeClassType().equals(BasicPrivilege.class)) {
+					privilegeToSet = value;
+				} else if (type.getPrivilegeClassType().equals(ObjectPrivilege.class)) {
+					if (value instanceof Map) {
+						privilegeToSet = ((Map<?, ?>) value).get(value);
+						objectId = (Integer) ((Map<?, ?>) value).get(objectId);
+					} else {
+						throw new QueryException("Invalid value for privilege: " + key);
+					}
+				} else {
+					throw new QueryException("Unknown privilege type: " + key);
+				}
+				if (objectId == null) {
+					getUserService().setUserPrivilege(modifiedUser, type, privilegeToSet, authenticationToken);
+				} else {
+					getUserService().setUserPrivilege(modifiedUser, type, privilegeToSet, objectId, authenticationToken);
+				}
+
+			}
+			return getUser(token, login, "");
+		} catch (IllegalArgumentException e) {
+			throw new QueryException("Invalid input", e);
+		}
+	}
+
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/users/UserRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/users/UserRestImplTest.java
index af81cc5eed..84d244b2db 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/users/UserRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/users/UserRestImplTest.java
@@ -1,6 +1,11 @@
 package lcsb.mapviewer.api.users;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 import org.junit.After;
@@ -10,8 +15,8 @@ import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import lcsb.mapviewer.api.RestTestFunctions;
-import lcsb.mapviewer.api.users.UserRestImpl;
 import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.model.user.PrivilegeType;
 
 public class UserRestImplTest extends RestTestFunctions {
 	Logger			 logger	= Logger.getLogger(UserRestImplTest.class);
@@ -42,6 +47,24 @@ public class UserRestImplTest extends RestTestFunctions {
 		}
 	}
 
+	@Test
+	public void testUpdatePrivileges() throws Exception {
+		try {
+			Map<String, Object> data = new HashMap<>();
+			data.put(PrivilegeType.ADD_MAP.name(), 1);
+			userRestImpl.updatePrivileges(adminToken.getId(), Configuration.ANONYMOUS_LOGIN, data);
+			assertTrue(userService.userHasPrivilege(userService.getUserByLogin(Configuration.ANONYMOUS_LOGIN), PrivilegeType.ADD_MAP));
+			
+			data.put(PrivilegeType.ADD_MAP.name(), 0);
+			userRestImpl.updatePrivileges(adminToken.getId(), Configuration.ANONYMOUS_LOGIN, data);
+			assertFalse(userService.userHasPrivilege(userService.getUserByLogin(Configuration.ANONYMOUS_LOGIN), PrivilegeType.ADD_MAP));
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw e;
+		}
+	}
+
 	@Test
 	public void testGetUsers() throws Exception {
 		try {
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
index 3c21473a35..d6f80c3fac 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
@@ -310,16 +310,9 @@ public class UserService implements IUserService {
 
 	@Override
 	public int getUserPrivilegeLevel(User user, PrivilegeType type, Object object) {
-		if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
-			throw new InvalidArgumentException("This privilege doesn't accept object parameter");
-		}
 		if (object == null) {
 			throw new InvalidArgumentException("Object cannot be null");
 		}
-		if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
-			throw new InvalidArgumentException(
-					"This privilege accept only " + type.getPrivilegeObjectType() + " objects parameter, but " + object.getClass() + " class found.");
-		}
 		Integer id = null;
 		try {
 			id = ObjectUtils.getIdOfObject(object);
@@ -327,6 +320,17 @@ public class UserService implements IUserService {
 			logger.error(e.getMessage(), e);
 			throw new InvalidArgumentException("Internal server error. Problem with accessing id of the parameter object");
 		}
+		if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
+			throw new InvalidArgumentException(
+					"This privilege accept only " + type.getPrivilegeObjectType() + " objects parameter, but " + object.getClass() + " class found.");
+		}
+		return getUserPrivilegeLevel(user, type, id);
+	}
+
+	private int getUserPrivilegeLevel(User user, PrivilegeType type, Integer id) {
+		if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
+			throw new InvalidArgumentException("This privilege doesn't accept object parameter");
+		}
 		if (id == null) {
 			throw new InvalidArgumentException("Parameter object has null id value");
 		}
@@ -355,8 +359,8 @@ public class UserService implements IUserService {
 	}
 
 	@Override
-	public void setUserPrivilege(User user, PrivilegeType type) {
-		BasicPrivilege privilege = new BasicPrivilege(1, type, user);
+	public void setUserPrivilege(User user, PrivilegeType type, Integer value) {
+		BasicPrivilege privilege = new BasicPrivilege(value, type, user);
 
 		BasicPrivilege oldPrivilege = null;
 		for (BasicPrivilege privilegeIter : user.getPrivileges()) {
@@ -590,4 +594,49 @@ public class UserService implements IUserService {
 			throw new SecurityException("You have no access to users data");
 		}
 	}
+
+	@Override
+	public void setUserPrivilege(User user, PrivilegeType type, Object value, AuthenticationToken token) throws SecurityException {
+		if (!userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+			throw new SecurityException("You cannot modify user privileges");
+		}
+		if (value instanceof Integer) {
+			setUserPrivilege(user, type, (Integer) value);
+		} else if (value instanceof Boolean) {
+			if ((Boolean) value) {
+				setUserPrivilege(user, type, 1);
+			} else {
+				setUserPrivilege(user, type, 0);
+			}
+		} else {
+			throw new InvalidArgumentException("Invalid privilege value: " + value);
+		}
+	}
+
+	@Override
+	public void setUserPrivilege(User user, PrivilegeType type, Object value, Integer objectId, AuthenticationToken token) throws SecurityException {
+		boolean canModify = userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
+		if (!canModify) {
+			if (type.getPrivilegeObjectType().isAssignableFrom(Project.class)) {
+				canModify = getUserPrivilegeLevel(getUserByToken(token), type, objectId) > 0;
+			}
+		}
+		if (!canModify) {
+			throw new SecurityException("You cannot modify user privileges");
+		}
+		Project projectIdWrapper = new Project();
+		projectIdWrapper.setId(objectId);
+		if (value instanceof Integer) {
+			setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, (Integer) value, type, user));
+		} else if (value instanceof Boolean) {
+			if ((Boolean) value) {
+				setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 1, type, user));
+			} else {
+				setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 0, type, user));
+			}
+		} else {
+			throw new InvalidArgumentException("Invalid privilege value: " + value);
+		}
+
+	}
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
index f9bfadc911..b6895941e0 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
@@ -201,7 +201,7 @@ public interface IUserService {
 	 * @param type
 	 *          type of the privilege
 	 */
-	void setUserPrivilege(User user, PrivilegeType type);
+	void setUserPrivilege(User user, PrivilegeType type, Integer value);
 
 	/**
 	 * Updates users from list of user
@@ -258,4 +258,8 @@ public interface IUserService {
 	User getUserById(String creatorId, AuthenticationToken authenticationToken) throws SecurityException;
 
 	List<User> getUsers(AuthenticationToken token) throws SecurityException;
+
+	void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, AuthenticationToken authenticationToken) throws SecurityException;
+
+	void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, Integer objectId, AuthenticationToken authenticationToken) throws SecurityException;
 }
diff --git a/web/src/test/java/lcsb/mapviewer/bean/ConfigurationBeanTest.java b/web/src/test/java/lcsb/mapviewer/bean/ConfigurationBeanTest.java
index de78f41fcc..6e2f4dad0d 100644
--- a/web/src/test/java/lcsb/mapviewer/bean/ConfigurationBeanTest.java
+++ b/web/src/test/java/lcsb/mapviewer/bean/ConfigurationBeanTest.java
@@ -33,8 +33,8 @@ public class ConfigurationBeanTest extends WebTestFunctions {
 
 		user2 = new User();
 		userService.addUser(user2);
-		userService.setUserPrivilege(user2, PrivilegeType.CONFIGURATION_MANAGE);
-		userService.setUserPrivilege(user2, PrivilegeType.ADD_MAP);
+		userService.setUserPrivilege(user2, PrivilegeType.CONFIGURATION_MANAGE, 1);
+		userService.setUserPrivilege(user2, PrivilegeType.ADD_MAP, 1);
 		uBean.setLoggedUser(user2);
 
 		oldValue = configurationService.getConfigurationValue(ConfigurationElementType.DEFAULT_MAP);
-- 
GitLab