/******************************************************************************* * Copyright (c) 2013 aegif. * * This file is part of NemakiWare. * * NemakiWare is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NemakiWare is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with NemakiWare. * If not, see <http://www.gnu.org/licenses/>. * * Contributors: * linzhixing(https://github.com/linzhixing) - initial API and implementation ******************************************************************************/ package jp.aegif.nemaki.rest; import java.text.SimpleDateFormat; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; 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.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import jp.aegif.nemaki.businesslogic.PrincipalService; import jp.aegif.nemaki.common.ErrorCode; import jp.aegif.nemaki.model.User; import jp.aegif.nemaki.util.AuthenticationUtil; import jp.aegif.nemaki.util.PropertyManager; import jp.aegif.nemaki.util.constant.PropertyKey; import org.apache.chemistry.opencmis.commons.server.CallContext; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.mindrot.jbcrypt.BCrypt; import org.springframework.stereotype.Component; @Component @Path("/repo/{repositoryId}/user/") public class UserResource extends ResourceBase { PrincipalService principalService; public void setPrincipalService(PrincipalService principalService) { this.principalService = principalService; } SolrResource solrResource; public void setSolrResource(SolrResource value){ this.solrResource = value; } private PropertyManager propertyManager; public void setPropertyManager(PropertyManager propertyManager) { this.propertyManager = propertyManager; } @SuppressWarnings("unchecked") @GET @Path("/list") @Produces(MediaType.APPLICATION_JSON) public String list(@PathParam("repositoryId") String repositoryId) { boolean status = true; JSONObject result = new JSONObject(); JSONArray listJSON = new JSONArray(); JSONArray errMsg = new JSONArray(); // Get all users list List<User> userList; try { userList = principalService.getUsers(repositoryId); for (User user : userList) { JSONObject userJSON = convertUserToJson(user); listJSON.add(userJSON); } result.put("users", listJSON); } catch (Exception e) { status = false; e.printStackTrace(); addErrMsg(errMsg, ITEM_ALLUSERS, ErrorCode.ERR_LIST); } result = makeResult(status, result, errMsg); return result.toJSONString(); } @SuppressWarnings("unchecked") @GET @Path("/show/{id}") @Produces(MediaType.APPLICATION_JSON) public String show(@PathParam("repositoryId") String repositoryId, @PathParam("id") String userId) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); // Validation if (StringUtils.isBlank(userId)) { status = false; addErrMsg(errMsg, ITEM_USERID, ErrorCode.ERR_MANDATORY); } User user = principalService.getUserById(repositoryId, userId); if (user == null) { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_NOTFOUND); } else { result.put("user", convertUserToJson(user)); } result = makeResult(status, result, errMsg); return result.toJSONString(); } /** * Search user by id TODO Use Solr * * @param query * @return */ @SuppressWarnings("unchecked") @GET @Path("/search") @Produces(MediaType.APPLICATION_JSON) public String search(@PathParam("repositoryId") String repositoryId, @QueryParam("query") String query) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); List<User> users; JSONArray queriedUsers = new JSONArray(); users = principalService.getUsers(repositoryId); for (User user : users) { if (user.getUserId().startsWith(query) || user.getName().startsWith(query)) { JSONObject userJSON = convertUserToJson(user); queriedUsers.add(userJSON); } } if (queriedUsers.isEmpty()) { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_NOTFOUND); } else { result.put("result", queriedUsers); } result = makeResult(status, result, errMsg); return result.toJSONString(); } @POST @Path("/create/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public String create(@PathParam("repositoryId") String repositoryId, @PathParam("id") String userId, @FormParam(FORM_USERNAME) String name, @FormParam(FORM_PASSWORD) String password, @FormParam(FORM_FIRSTNAME) String firstName, @FormParam(FORM_LASTNAME) String lastName, @FormParam(FORM_EMAIL) String email, @Context HttpServletRequest httpRequest) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); // Validation status = validateNewUser(status, errMsg, userId, name, firstName, lastName, password, repositoryId); // Create a user if (status) { // initialize mandatory but space-allowed parameters if (StringUtils.isBlank(lastName)) lastName = ""; if (StringUtils.isBlank(email)) email = ""; // Generate a password hash String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt()); User user = new User(userId, name, firstName, lastName, email, passwordHash); setFirstSignature(httpRequest, user); // TODO Error handling principalService.createUser(repositoryId, user); } result = makeResult(status, result, errMsg); return result.toJSONString(); } @PUT @Path("/changePassword/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public String changePassword(@PathParam("repositoryId") String repositoryId, @PathParam("id") String userId, @FormParam(FORM_OLDPASSWORD) String oldPassword, @FormParam(FORM_NEWPASSWORD) String newPassword, @Context HttpServletRequest httpRequest) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); User user = principalService.getUserById(repositoryId, userId); // Validation status = checkAuthorityForUser(status, errMsg, httpRequest, userId, repositoryId); if (status) { if (!AuthenticationUtil.passwordMatches(oldPassword, user.getPasswordHash())) { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_WRONGPASSWORD); } // Edit & Update if (status) { // Edit the user info String passwordHash = BCrypt.hashpw(newPassword, BCrypt.gensalt()); user.setPasswordHash(passwordHash); setModifiedSignature(httpRequest, user); try { principalService.updateUser(repositoryId, user); } catch (Exception e) { e.printStackTrace(); status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_UPDATE); } setModifiedSignature(httpRequest, user); try { principalService.updateUser(repositoryId, user); } catch (Exception e) { e.printStackTrace(); status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_UPDATE); } if(status){ String solrUserId = propertyManager.readValue(PropertyKey.SOLR_NEMAKI_USERID); if(user.getUserId().equals(solrUserId)){ JSONObject capResult = solrResource.changeAdminPasswordImpl(repositoryId, newPassword, oldPassword, httpRequest); if (capResult.get(ITEM_STATUS).toString() != SUCCESS){ // TODO: Error handling status = false; addErrMsg(errMsg, ITEM_USER, capResult.get(ITEM_ERROR).toString()); } } } } } makeResult(status, result, errMsg); return result.toJSONString(); } @PUT @Path("/update/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public String update(@PathParam("repositoryId") String repositoryId, @PathParam("id") String userId, @FormParam(FORM_USERNAME) String name, @FormParam(FORM_FIRSTNAME) String firstName, @FormParam(FORM_LASTNAME) String lastName, @FormParam(FORM_EMAIL) String email, @FormParam("addFavorites") String addFavorites, @FormParam("removeFavorites") String removeFavorites, @FormParam(FORM_PASSWORD) String password, @Context HttpServletRequest httpRequest) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); // Existing user User user = principalService.getUserById(repositoryId, userId); // Validation status = checkAuthorityForUser(status, errMsg, httpRequest, userId, repositoryId); // status = validateUser(status, errMsg, userId, name, firstName, // lastName); // Edit & Update if (status) { // Edit the user info // if a parameter is not input, it won't be modified. if (userId != null) user.setUserId(userId); if (name != null) user.setName(name); if (firstName != null) user.setFirstName(firstName); if (lastName != null) user.setLastName(lastName); if (email != null) user.setEmail(email); if (addFavorites != null) { try { JSONArray l = (JSONArray) (new JSONParser().parse(addFavorites)); Set<String> fs = user.getFavorites(); if (CollectionUtils.isEmpty(fs)) { fs = new HashSet<String>(); } fs.addAll(l); user.setFavorites(fs); System.out.println(); // fs.addAll(l); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (removeFavorites != null) { try { JSONArray l = (JSONArray) (new JSONParser().parse(removeFavorites)); user.getFavorites().removeAll(l); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (StringUtils.isNotBlank(password)) { // TODO Error handling user = principalService.getUserById(repositoryId, userId); // Edit & Update if (status) { // Edit the user info String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt()); user.setPasswordHash(passwordHash); setModifiedSignature(httpRequest, user); try { principalService.updateUser(repositoryId, user); } catch (Exception e) { e.printStackTrace(); status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_UPDATE); } } } setModifiedSignature(httpRequest, user); try { principalService.updateUser(repositoryId, user); } catch (Exception e) { e.printStackTrace(); status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_UPDATE); } } makeResult(status, result, errMsg); return result.toJSONString(); } @DELETE @Path("/delete/{id}") @Produces(MediaType.APPLICATION_JSON) public String delete(@PathParam("repositoryId") String repositoryId, @PathParam("id") String userId, @Context HttpServletRequest httpRequest) { boolean status = true; JSONObject result = new JSONObject(); JSONArray errMsg = new JSONArray(); // Existing user User user = principalService.getUserById(repositoryId, userId); if (user == null) { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_NOTFOUND); } // Validation status = checkAuthorityForUser(status, errMsg, httpRequest, userId, repositoryId); // Delete a user if (status) { try { principalService.deleteUser(repositoryId, user.getId()); } catch (Exception ex) { ex.printStackTrace(); status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_DELETE); } } else { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_DELETE); } result = makeResult(status, result, errMsg); return result.toJSONString(); } private boolean validateUser(boolean status, JSONArray errMsg, String userId, String userName, String firstName, String lastName) { if (StringUtils.isBlank(userId)) { status = false; addErrMsg(errMsg, ITEM_USERID, ErrorCode.ERR_MANDATORY); } if (StringUtils.isBlank(userName)) { status = false; addErrMsg(errMsg, ITEM_USERNAME, ErrorCode.ERR_MANDATORY); } return status; } private boolean validateNewUser(boolean status, JSONArray errMsg, String userId, String userName, String firstName, String lastName, String password, String repositoryId) { status = validateUser(status, errMsg, userId, userName, firstName, lastName); // userID uniqueness User user = principalService.getUserById(repositoryId, userId); if (user != null) { status = false; addErrMsg(errMsg, ITEM_USERID, ErrorCode.ERR_ALREADYEXISTS); } if (StringUtils.isBlank(password)) { status = false; addErrMsg(errMsg, ITEM_PASSWORD, ErrorCode.ERR_MANDATORY); } return status; } @SuppressWarnings("unchecked") private JSONObject convertUserToJson(User user) { SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); String created = new String(); try { if (user.getCreated() != null) { created = sdf.format(user.getCreated().getTime()); } } catch (Exception ex) { ex.printStackTrace(); } String modified = new String(); try { if (user.getModified() != null) { modified = sdf.format(user.getModified().getTime()); } } catch (Exception ex) { ex.printStackTrace(); } JSONObject userJSON = new JSONObject(); userJSON.clear(); userJSON.put(ITEM_USERID, user.getUserId()); userJSON.put(ITEM_USERNAME, user.getName()); userJSON.put(ITEM_FIRSTNAME, user.getFirstName()); userJSON.put(ITEM_LASTNAME, user.getLastName()); userJSON.put(ITEM_EMAIL, user.getEmail()); userJSON.put(ITEM_TYPE, user.getType()); userJSON.put(ITEM_CREATOR, user.getCreator()); userJSON.put(ITEM_CREATED, created); userJSON.put(ITEM_MODIFIER, user.getModifier()); userJSON.put(ITEM_MODIFIED, modified); boolean isAdmin = (user.isAdmin() == null) ? false : user.isAdmin(); userJSON.put(ITEM_IS_ADMIN, isAdmin); JSONArray jfs = new JSONArray(); Set<String> ufs = user.getFavorites(); if (CollectionUtils.isNotEmpty(ufs)) { Iterator<String> ufsItr = ufs.iterator(); while (ufsItr.hasNext()) { jfs.add(ufsItr.next()); } } userJSON.put("favorites", jfs); return userJSON; } private boolean checkAuthorityForUser(boolean status, JSONArray errMsg, HttpServletRequest httpRequest, String resoureId, String repositoryId) { CallContext callContext = (CallContext) httpRequest.getAttribute("CallContext"); String userId = callContext.getUsername(); String password = callContext.getPassword(); if (!userId.equals(resoureId) && !isAdminOperaiton(repositoryId, userId, password) && !isSystemUser(repositoryId, resoureId)) { status = false; addErrMsg(errMsg, ITEM_USER, ErrorCode.ERR_NOTAUTHENTICATED); } return status; } private boolean isSystemUser(String repositoryId, String userId){ boolean result = false; User user = principalService.getUserById(repositoryId, userId); result = user.isAdmin(); if(result) return true; String solrUserId = propertyManager.readValue(PropertyKey.SOLR_NEMAKI_USERID); result = user.getUserId().equals(solrUserId); if(result) return true; return result; } private boolean isAdminOperaiton(String repositoryId, String userId, String password) { if (StringUtils.isBlank(userId) || StringUtils.isBlank(password)) { return false; } User user = principalService.getUserById(repositoryId, userId); boolean isAdmin = (user.isAdmin() == null) ? false : user.isAdmin(); if (isAdmin) { // password check boolean match = BCrypt.checkpw(password, user.getPasswordHash()); if (match) return true; } return false; } }