Java tutorial
/* * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org> * * This file is part of the Kitodo project. * * It is licensed under GNU General Public License version 3 or later. * * For the full copyright and license information, please read the * GPL3-License.txt file that was distributed with this source code. */ package org.kitodo.production.services.data; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.LocalDateTime; import org.kitodo.config.ConfigCore; import org.kitodo.config.enums.KitodoConfigFile; import org.kitodo.config.enums.ParameterCore; import org.kitodo.data.database.beans.Client; import org.kitodo.data.database.beans.Filter; import org.kitodo.data.database.beans.Task; import org.kitodo.data.database.beans.User; import org.kitodo.data.database.enums.TaskStatus; import org.kitodo.data.database.exceptions.DAOException; import org.kitodo.data.database.persistence.UserDAO; import org.kitodo.data.exceptions.DataException; import org.kitodo.production.dto.UserDTO; import org.kitodo.production.helper.Helper; import org.kitodo.production.security.SecurityUserDetails; import org.kitodo.production.security.password.SecurityPasswordEncoder; import org.kitodo.production.services.ServiceManager; import org.kitodo.production.services.data.base.SearchDatabaseService; import org.primefaces.model.SortOrder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class UserService extends SearchDatabaseService<User, UserDAO> implements UserDetailsService { private static final Logger logger = LogManager.getLogger(UserService.class); private static UserService instance = null; private static final String CLIENT_ID = "clientId"; private SecurityPasswordEncoder passwordEncoder = new SecurityPasswordEncoder(); private static final int DEFAULT_CLIENT_ID = ConfigCore .getIntParameterOrDefaultValue(ParameterCore.DEFAULT_CLIENT_ID); /** * Constructor. */ private UserService() { super(new UserDAO()); } /** * Return singleton variable of type UserService. * * @return unique instance of UserService */ public static UserService getInstance() { if (Objects.equals(instance, null)) { synchronized (UserService.class) { if (Objects.equals(instance, null)) { instance = new UserService(); } } } return instance; } @Override public Long countDatabaseRows() throws DAOException { return countDatabaseRows("SELECT COUNT(*) FROM User WHERE deleted = 0"); } @Override public Long countResults(Map filters) throws DAOException { if (ServiceManager.getSecurityAccessService().hasAuthorityGlobalToViewUserList()) { return countDatabaseRows(); } if (ServiceManager.getSecurityAccessService().hasAuthorityToViewUserList()) { return countDatabaseRows( "SELECT COUNT(*) FROM User u INNER JOIN u.clients AS c WITH c.id = :clientId WHERE deleted = 0", Collections.singletonMap(CLIENT_ID, getSessionClientId())); } return 0L; } @Override public List<User> getAllForSelectedClient() { return getByQuery( "SELECT u FROM User AS u INNER JOIN u.clients AS c WITH c.id = :clientId WHERE deleted = 0", Collections.singletonMap(CLIENT_ID, getSessionClientId())); } @Override public UserDetails loadUserByUsername(String username) { return new SecurityUserDetails(getByLogin(username)); } @Override @SuppressWarnings("unchecked") public List<User> loadData(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) { if (ServiceManager.getSecurityAccessService().hasAuthorityGlobalToViewUserList()) { return dao.getByQuery("FROM User WHERE deleted = 0" + getSort(sortField, sortOrder), filters, first, pageSize); } if (ServiceManager.getSecurityAccessService().hasAuthorityToViewUserList()) { return dao.getByQuery( "SELECT u FROM User AS u INNER JOIN u.clients AS c WITH c.id = :clientId WHERE deleted = 0" + getSort(sortField, sortOrder), Collections.singletonMap(CLIENT_ID, getSessionClientId()), first, pageSize); } return new ArrayList<>(); } /** * Gets user by ldap login and in case that no user can be found the normal * login is used as fallback. * * @param login * The login of the user. * @return The user object. * @throws UsernameNotFoundException * if no user can be found by ldap login and normal login */ public User getByLdapLoginWithFallback(String login) { User user; try { user = getByLdapLogin(login); } catch (UsernameNotFoundException e) { user = getByLogin(login); } return user; } /** * Gets user by login. * * @param login * The login. * @return The user. */ public User getByLogin(String login) { return getByLoginQuery(login, "from User where login = :login"); } /** * Gets user by ldap login. * * @param ldapLogin * The ldapLogin. * @return The user. */ public User getByLdapLogin(String ldapLogin) { return getByLoginQuery(ldapLogin, "from User where ldapLogin = :login"); } private User getByLoginQuery(String login, String query) { List<User> users = getByQuery(query, Collections.singletonMap("login", login)); if (users.size() == 1) { return users.get(0); } else if (users.isEmpty()) { throw new UsernameNotFoundException("Login " + login + " not found!"); } else { throw new UsernameNotFoundException("Login " + login + " was found more than once"); } } /** * Gets the current authenticated user of current threads security context. * * @return The SecurityUserDetails object or null if no user is authenticated. */ public SecurityUserDetails getAuthenticatedUser() { return ServiceManager.getSecurityAccessService().getAuthenticatedSecurityUserDetails(); } /** * Get the current authenticated user as User bean. * * @return the User object */ public User getCurrentUser() { return new User(getAuthenticatedUser()); } /** * Gets the session client of the current authenticated user. * * @return The client object or null if no session client is set or no user is * authenticated. */ public Client getSessionClientOfAuthenticatedUser() { if (Objects.nonNull(getAuthenticatedUser())) { return getAuthenticatedUser().getSessionClient(); } else { return null; } } /** * Gets the selected session client id of the current authenticated user. * * @return session client id */ public int getSessionClientId() { if (Objects.nonNull(getSessionClientOfAuthenticatedUser())) { return getSessionClientOfAuthenticatedUser().getId(); } return DEFAULT_CLIENT_ID; } /** * Get amount of users with exactly the same login like given but different id. * * @param id * of user * @param login * of user * @return amount of users with exactly the same login like given but different * id */ public Long getAmountOfUsersWithExactlyTheSameLogin(Integer id, String login) throws DAOException { return dao.countUsersWithExactlyTheSameLogin(id, login); } /** * Get all active users sorted by surname and name. * * @return sorted list of all active users as User objects */ public List<User> getAllActiveUsersSortedByNameAndSurname() { return dao.getAllActiveUsersSortedByNameAndSurname(); } /** * Check validity of given login. * * @param login * to validation * @return true or false */ public boolean isLoginValid(String login) { String patternString = "[A-Za-z0-9@_\\-.]*"; Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(login); if (!matcher.matches()) { return false; } return isLoginAllowed(login); } private boolean isLoginAllowed(String login) { // If user defined blacklist doesn't exists, use default one if (!KitodoConfigFile.LOGIN_BLACKLIST.exists()) { ClassLoader classloader = Thread.currentThread().getContextClassLoader(); try (InputStream inputStream = classloader .getResourceAsStream(KitodoConfigFile.LOGIN_BLACKLIST.getName()); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(inputStreamReader)) { if (isLoginFoundOnBlackList(reader, login)) { return false; } } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); return false; } } // Go through the user defined blacklist file line by line and compare with login try (FileInputStream inputStream = new FileInputStream(KitodoConfigFile.LOGIN_BLACKLIST.getFile()); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(inputStreamReader)) { if (isLoginFoundOnBlackList(reader, login)) { return false; } } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); return false; } return true; } private boolean isLoginFoundOnBlackList(BufferedReader reader, String login) throws IOException { String notAllowedLogin; while ((notAllowedLogin = reader.readLine()) != null) { if (notAllowedLogin.length() > 0 && login.equalsIgnoreCase(notAllowedLogin)) { return true; } } return false; } public String getFullName(User user) { return user.getSurname() + ", " + user.getName(); } /** * At that moment only add this method. * * @param user * object as UserDTo * @return full name of the user as String */ public String getFullName(UserDTO user) { return user.getSurname() + ", " + user.getName(); } /** * Get user home directory (either from the LDAP or directly from the * configuration). If LDAP is used, find home directory there, otherwise in * configuration. * * @return path as String * @throws IOException * add description */ public URI getHomeDirectory(User user) throws IOException { URI result; if (Objects.nonNull(user)) { if (ConfigCore.getBooleanParameterOrDefaultValue(ParameterCore.LDAP_USE)) { result = Paths.get(ServiceManager.getLdapServerService().getUserHomeDirectory(user)).toUri(); } else { result = Paths.get(ConfigCore.getParameter(ParameterCore.DIR_USERS), user.getLogin()).toUri(); } if (!new File(result).exists()) { ServiceManager.getFileService().createDirectoryForUser(result, user.getLogin()); } } else { throw new IOException("No user for home directory!"); } return result; } /** * Adds a new filter to list. * * @param user * object * @param filter * the filter to add */ public void addFilter(User user, String filter) { if (getFilters(user).contains(filter)) { return; } try { addFilterToUser(user, filter); } catch (DataException e) { logger.error("Cannot not add filter to user with id " + user.getId(), e); } } /** * Removes filter from list. * * @param user * object * @param filter * the filter to remove */ public void removeFilter(User user, String filter) { if (!getFilters(user).contains(filter)) { return; } try { removeFilterFromUser(user, filter); } catch (DataException e) { logger.error("Cannot not remove filter from user with id " + user.getId(), e); } } /** * Get list of filters. * * @param user * object * @return List of filters as strings */ public List<String> getFilters(User user) { return getFiltersForUser(user); } /** * Add filter to user. * * @param user * object * @param userFilter * String */ private void addFilterToUser(User user, String userFilter) throws DataException { LocalDateTime localDateTime = new LocalDateTime(); Filter filter = new Filter(); filter.setValue(userFilter); filter.setCreationDate(localDateTime.toDate()); filter.setUser(user); ServiceManager.getFilterService().save(filter); refresh(user); } /** * Get filters for user. * * @param user * object * @return list of filters */ private List<String> getFiltersForUser(User user) { List<String> userFilters = new ArrayList<>(); List<Filter> filters = user.getFilters(); for (Filter filter : filters) { userFilters.add(filter.getValue()); } return userFilters; } /** * Remove filter from user. * * @param user * object * @param userFilter * String */ private void removeFilterFromUser(User user, String userFilter) throws DataException { List<Filter> filters = user.getFilters(); for (Filter filter : filters) { if (filter.getValue().equals(userFilter)) { ServiceManager.getFilterService().remove(filter); } } refresh(user); } /** * Retrieve and return the list of tasks that are assigned to the user and * that are "INWORK" and belong to process, not template. * * @return list of tasks that are currently assigned to the user and that * are "INWORK" and belong to process, not template */ public List<Task> getTasksInProgress(User user) { return user.getProcessingTasks().stream().filter( task -> task.getProcessingStatus().equals(TaskStatus.INWORK) && Objects.nonNull(task.getProcess())) .collect(Collectors.toList()); } /** * Changes the password for given User object. * * @param user * The User object. * @param newPassword * The new password. */ public void changeUserPassword(User user, String newPassword) throws DAOException { User userWithNewPassword; if (user instanceof SecurityUserDetails) { userWithNewPassword = new User(user); } else { userWithNewPassword = user; } userWithNewPassword.setPassword(passwordEncoder.encrypt(newPassword)); saveToDatabase(userWithNewPassword); } }