/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.api.impl; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Person; import org.openmrs.Privilege; import org.openmrs.Role; import org.openmrs.User; import org.openmrs.api.APIAuthenticationException; import org.openmrs.api.APIException; import org.openmrs.api.UserService; import org.openmrs.api.context.Context; import org.openmrs.api.db.DAOException; import org.openmrs.api.db.UserDAO; import org.openmrs.patient.impl.LuhnIdentifierValidator; import org.openmrs.util.OpenmrsConstants; /** * Default implementation of the user service. This class should not be used on its own. The current * OpenMRS implementation should be fetched from the Context * * @see org.openmrs.api.UserService * @see org.openmrs.api.context.Context */ public class UserServiceImpl extends BaseOpenmrsService implements UserService { private static Log log = LogFactory.getLog(UserServiceImpl.class); protected UserDAO dao; public UserServiceImpl() { } public void setUserDAO(UserDAO dao) { this.dao = dao; } /** * @see org.openmrs.api.UserService#createUser(org.openmrs.User, java.lang.String) * @deprecated */ public User createUser(User user, String password) throws APIException { return Context.getUserService().saveUser(user, password); } /** * @see org.openmrs.api.UserService#saveUser(org.openmrs.User, java.lang.String) */ public User saveUser(User user, String password) throws APIException { if (user.getUserId() == null) { Context.requirePrivilege(OpenmrsConstants.PRIV_ADD_USERS); } else { Context.requirePrivilege(OpenmrsConstants.PRIV_EDIT_USERS); } checkPrivileges(user); // if we're creating a user and a password wasn't supplied, throw an // error if (user.getUserId() == null && (password == null || password.length() < 1)) throw new APIException("A password is required when creating a user"); if (hasDuplicateUsername(user)) throw new DAOException("Username " + user.getUsername() + " or system id " + user.getSystemId() + " is already in use."); // TODO Check required fields for user!! return dao.saveUser(user, password); } /** * @see org.openmrs.api.UserService#getUser(java.lang.Integer) */ public User getUser(Integer userId) throws APIException { return dao.getUser(userId); } /** * @see org.openmrs.api.UserService#getUserByUsername(java.lang.String) */ public User getUserByUsername(String username) throws APIException { return dao.getUserByUsername(username); } /** * @see org.openmrs.api.UserService#hasDuplicateUsername(org.openmrs.User) */ public boolean hasDuplicateUsername(User user) throws APIException { return dao.hasDuplicateUsername(user.getUsername(), user.getSystemId(), user.getUserId()); } /** * @see org.openmrs.api.UserService#getUsersByRole(org.openmrs.Role) */ public List<User> getUsersByRole(Role role) throws APIException { List<Role> roles = new Vector<Role>(); roles.add(role); return getUsers(null, roles, false); } /** * @deprecated replaced by {@link #saveUser(User, String)} * @see org.openmrs.api.UserService#updateUser(org.openmrs.User) */ public void updateUser(User user) throws APIException { Context.getUserService().saveUser(user, null); } /** * @see org.openmrs.api.UserService#grantUserRole(org.openmrs.User, org.openmrs.Role) * @deprecated */ public void grantUserRole(User user, Role role) throws APIException { Context.getUserService().saveUser(user.addRole(role), null); } /** * @see org.openmrs.api.UserService#revokeUserRole(org.openmrs.User, org.openmrs.Role) * @deprecated */ public void revokeUserRole(User user, Role role) throws APIException { Context.getUserService().saveUser(user.removeRole(role), null); } /** * @see org.openmrs.api.UserService#voidUser(org.openmrs.User, java.lang.String) */ public User voidUser(User user, String reason) throws APIException { return Context.getUserService().retireUser(user, reason); } /** * @see org.openmrs.api.UserService#retireUser(org.openmrs.User, java.lang.String) */ public User retireUser(User user, String reason) throws APIException { user.setRetired(true); user.setRetireReason(reason); user.setRetiredBy(Context.getAuthenticatedUser()); user.setDateRetired(new Date()); return saveUser(user, null); } /** * @see org.openmrs.api.UserService#unvoidUser(org.openmrs.User) */ public User unvoidUser(User user) throws APIException { return Context.getUserService().unretireUser(user); } /** * @see org.openmrs.api.UserService#unretireUser(org.openmrs.User) */ public User unretireUser(User user) throws APIException { user.setRetired(false); user.setRetireReason(null); user.setRetiredBy(null); user.setDateRetired(null); return saveUser(user, null); } /** * @see org.openmrs.api.UserService#deleteUser(org.openmrs.User) * @deprecated */ public void deleteUser(User user) throws APIException { Context.getUserService().purgeUser(user); } /** * @see org.openmrs.api.UserService#getUsers() * @deprecated */ public List<User> getUsers() throws APIException { return getAllUsers(); } /** * @see org.openmrs.api.UserService#getAllUsers() */ public List<User> getAllUsers() throws APIException { return dao.getAllUsers(); } /** * @see org.openmrs.api.UserService#getPrivileges() * @deprecated */ public List<Privilege> getPrivileges() throws APIException { return getAllPrivileges(); } /** * @see org.openmrs.api.UserService#getAllPrivileges() */ public List<Privilege> getAllPrivileges() throws APIException { return dao.getAllPrivileges(); } /** * @see org.openmrs.api.UserService#getPrivilege(java.lang.String) */ public Privilege getPrivilege(String p) throws APIException { return dao.getPrivilege(p); } /** * @see org.openmrs.api.UserService#purgePrivilege(org.openmrs.Privilege) */ public void purgePrivilege(Privilege privilege) throws APIException { if (OpenmrsConstants.CORE_PRIVILEGES().keySet().contains(privilege.getPrivilege())) throw new APIException("Cannot delete a core privilege"); dao.deletePrivilege(privilege); } /** * @see org.openmrs.api.UserService#savePrivilege(org.openmrs.Privilege) */ public Privilege savePrivilege(Privilege privilege) throws APIException { return dao.savePrivilege(privilege); } /** * @see org.openmrs.api.UserService#getRoles() * @deprecated */ public List<Role> getRoles() throws APIException { return getAllRoles(); } /** * @see org.openmrs.api.UserService#getAllRoles() */ public List<Role> getAllRoles() throws APIException { return dao.getAllRoles(); } /** * @see org.openmrs.api.UserService#getInheritingRoles(org.openmrs.Role) * @deprecated */ public List<Role> getInheritingRoles(Role role) throws APIException { List<Role> roles = new Vector<Role>(); roles.addAll(role.getInheritedRoles()); return roles; } /** * @see org.openmrs.api.UserService#getRole(java.lang.String) */ public Role getRole(String r) throws APIException { return dao.getRole(r); } /** * @see org.openmrs.api.UserService#purgeRole(org.openmrs.Role) */ public void purgeRole(Role role) throws APIException { if (role == null || role.getRole() == null) return; if (OpenmrsConstants.CORE_ROLES().keySet().contains(role.getRole())) throw new APIException("Cannot delete a core role"); dao.deleteRole(role); } /** * @see org.openmrs.api.UserService#saveRole(org.openmrs.Role) */ public Role saveRole(Role role) throws APIException { // make sure one of the parents of this role isn't itself...this would // cause an infinite loop if (role.getAllParentRoles().contains(role)) throw new APIAuthenticationException("Invalid Role or parent Role. A role cannot inherit itself."); checkPrivileges(role); return dao.saveRole(role); } /** * @see org.openmrs.api.UserService#changePassword(org.openmrs.User, java.lang.String) */ public void changePassword(User u, String pw) throws APIException { dao.changePassword(u, pw); } /** * @see org.openmrs.api.UserService#changePassword(java.lang.String, java.lang.String) */ public void changePassword(String pw, String pw2) throws APIException { dao.changePassword(pw, pw2); } /** * @see org.openmrs.api.UserService#changeHashedPassword(User, String, String) */ public void changeHashedPassword(User user, String hashedPassword, String salt) throws APIException { dao.changeHashedPassword(user, hashedPassword, salt); } /** * @see org.openmrs.api.UserService#changeQuestionAnswer(User, String, String) */ public void changeQuestionAnswer(User u, String question, String answer) throws APIException { dao.changeQuestionAnswer(u, question, answer); } /** * @see org.openmrs.api.UserService#changeQuestionAnswer(java.lang.String, java.lang.String, * java.lang.String) */ public void changeQuestionAnswer(String pw, String q, String a) { dao.changeQuestionAnswer(pw, q, a); } /** * @see org.openmrs.api.UserService#isSecretAnswer(org.openmrs.User, java.lang.String) */ public boolean isSecretAnswer(User u, String answer) { return dao.isSecretAnswer(u, answer); } /** * @see org.openmrs.api.UserService#findUsers(String, List, boolean) * @deprecated */ public List<User> findUsers(String name, List<String> roles, boolean includeVoided) { List<Role> rolesToSearch = new Vector<Role>(); for (String role : roles) { rolesToSearch.add(new Role(role)); } return getUsers(name, rolesToSearch, includeVoided); } /** * @see org.openmrs.api.UserService#findUsers(String, String, boolean) * @deprecated */ public List<User> findUsers(String givenName, String familyName, boolean includeVoided) { return getUsersByName(givenName, familyName, includeVoided); } /** * @see org.openmrs.api.UserService#getUsersByName(java.lang.String, java.lang.String, boolean) */ public List<User> getUsersByName(String givenName, String familyName, boolean includeVoided) throws APIException { return dao.getUsersByName(givenName, familyName, includeVoided); } /** * @see org.openmrs.api.UserService#getUsersByPerson(org.openmrs.Person, boolean) */ public List<User> getUsersByPerson(Person person, boolean includeRetired) throws APIException { return dao.getUsersByPerson(person, includeRetired); } /** * @see org.openmrs.api.UserService#getAllUsers(List, boolean) * @deprecated */ public List<User> getAllUsers(List<Role> roles, boolean includeVoided) { return getUsers(null, roles, includeVoided); } /** * @see org.openmrs.api.UserService#getUsers(java.lang.String, java.util.List, boolean) */ public List<User> getUsers(String nameSearch, List<Role> roles, boolean includeVoided) throws APIException { if (nameSearch != null) nameSearch = nameSearch.replace(", ", " "); if (roles == null) roles = new Vector<Role>(); // if the authenticated role is in the list of searched roles, then all // persons should be searched Role auth_role = getRole(OpenmrsConstants.AUTHENTICATED_ROLE); if (roles.contains(auth_role)) return dao.getUsers(nameSearch, new Vector<Role>(), includeVoided); else return dao.getUsers(nameSearch, roles, includeVoided); } /** * Convenience method to check if the authenticated user has all privileges they are giving out * * @param new user that has privileges */ private void checkPrivileges(User user) { Collection<Role> roles = user.getAllRoles(); User authUser = Context.getAuthenticatedUser(); List<String> requiredPrivs = new Vector<String>(); for (Role r : roles) { if (r.getRole().equals(OpenmrsConstants.SUPERUSER_ROLE) && !authUser.hasRole(OpenmrsConstants.SUPERUSER_ROLE)) throw new APIException("You must have the role '" + OpenmrsConstants.SUPERUSER_ROLE + "' in order to assign it."); if (r.getPrivileges() != null) { for (Privilege p : r.getPrivileges()) if (!authUser.hasPrivilege(p.getPrivilege())) requiredPrivs.add(p.getPrivilege()); } } if (requiredPrivs.size() == 1) { throw new APIException("You must have privilege '" + requiredPrivs.get(0) + "' in order to assign it."); } else if (requiredPrivs.size() > 1) { String txt = "You must have the following privileges in order to assign them: "; for (String s : requiredPrivs) txt += s + ", "; txt = txt.substring(0, txt.length() - 2); throw new APIException(txt); } } /** * @see org.openmrs.api.UserService#setUserProperty(User, String, String) */ public User setUserProperty(User user, String key, String value) { if (user != null) { if (!Context.hasPrivilege(OpenmrsConstants.PRIV_EDIT_USERS) && !user.equals(Context.getAuthenticatedUser())) throw new APIException("You are not authorized to change " + user.getUserId() + "'s properties"); user.setUserProperty(key, value); try { Context.addProxyPrivilege(OpenmrsConstants.PRIV_EDIT_USERS); saveUser(user, null); } finally { Context.removeProxyPrivilege(OpenmrsConstants.PRIV_EDIT_USERS); } } return user; } /** * @see org.openmrs.api.UserService#removeUserProperty(org.openmrs.User, java.lang.String) */ public User removeUserProperty(User user, String key) { if (user != null) { // if the current user isn't allowed to edit users and // the user being edited is not the current user, throw an // exception if (!Context.hasPrivilege(OpenmrsConstants.PRIV_EDIT_USERS) && !user.equals(Context.getAuthenticatedUser())) throw new APIException("You are not authorized to change " + user.getUserId() + "'s properties"); user.removeUserProperty(key); try { Context.addProxyPrivilege(OpenmrsConstants.PRIV_EDIT_USERS); saveUser(user, null); } finally { Context.removeProxyPrivilege(OpenmrsConstants.PRIV_EDIT_USERS); } } return user; } /** * Generates system ids based on the following algorithm scheme: user_id-check * digit * * @see org.openmrs.api.UserService#generateSystemId() */ public String generateSystemId() { // Hardcoding Luhn algorithm since all existing openmrs user ids have // had check digits generated this way. LuhnIdentifierValidator liv = new LuhnIdentifierValidator(); String systemId; Integer offset = 0; do { // generate and increment the system id if necessary Integer generatedId = dao.generateSystemId() + offset++; systemId = generatedId.toString(); try { systemId = liv.getValidIdentifier(systemId); } catch (Exception e) { log.error("error getting check digit", e); return systemId; } // loop until we find a system id that no one has } while (dao.hasDuplicateUsername(null, systemId, null)); return systemId; } /** * @see org.openmrs.api.UserService#purgeUser(org.openmrs.User) */ public void purgeUser(User user) throws APIException { dao.deleteUser(user); } /** * @see org.openmrs.api.UserService#purgeUser(org.openmrs.User, boolean) */ public void purgeUser(User user, boolean cascade) throws APIException { if (cascade == true) { throw new APIException("I don't think we want to cascade here"); } dao.deleteUser(user); } /** * Convenience method to check if the authenticated user has all privileges they are giving out * to the new role * * @param new user that has privileges */ private void checkPrivileges(Role role) { Collection<Privilege> privileges = role.getPrivileges(); if (privileges != null) for (Privilege p : privileges) { if (!Context.hasPrivilege(p.getPrivilege())) throw new APIAuthenticationException("Privilege required: " + p); } } /** * @see org.openmrs.api.UserService#getPrivilegeByUuid(java.lang.String) */ public Privilege getPrivilegeByUuid(String uuid) throws APIException { return dao.getPrivilegeByUuid(uuid); } /** * @see org.openmrs.api.UserService#getRoleByUuid(java.lang.String) */ public Role getRoleByUuid(String uuid) throws APIException { return dao.getRoleByUuid(uuid); } /** * @see org.openmrs.api.UserService#getUserByUuid(java.lang.String) */ public User getUserByUuid(String uuid) throws APIException { return dao.getUserByUuid(uuid); } }