package org.appfuse.webapp.server.services.impl; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Set; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.RandomUtils; import org.appfuse.Constants; import org.appfuse.model.Role; import org.appfuse.model.User; import org.appfuse.service.RoleManager; import org.appfuse.service.UserExistsException; import org.appfuse.service.UserManager; import org.appfuse.webapp.client.proxies.RoleProxy; import org.appfuse.webapp.listener.UserCounterListener; import org.appfuse.webapp.server.services.UserRequestService; import org.appfuse.webapp.server.services.UsersSearchCriteria; import org.appfuse.webapp.util.RequestUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.support.PropertyComparator; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.mail.MailException; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; import org.springframework.stereotype.Component; @Component("userRequestService") public class UserRequestServiceImpl extends AbstractBaseRequest implements UserRequestService { public static final String RECOVERY_PASSWORD_TEMPLATE = "/#updatePassword:username={username}!token={token}"; @Autowired private UserManager userManager; @Autowired private RoleManager roleManager; /** * * @return */ @Override public User getCurrentUser() { final String username = getCurrentUsername(); if (username != null) { final User user = userManager.getUserByUsername(username); if (isFullyAuthenticated()) { user.getRoles().add(new Role(RoleProxy.FULLY_AUTHENTICATED)); } return user; } return null; } /** * * @return */ @Override public User signUp() { return new User(); } /** * * @param user * @return * @throws Exception */ @Override public User signUp(final User user) throws Exception { user.setEnabled(true); // Set the default user role on this new user user.getRoles().clear(); user.addRole(roleManager.getRole(Constants.USER_ROLE)); try { userManager.saveUser(user); } catch (final UserExistsException e) { log.debug(String.format("Trying to duplicate user username=%s, email=%d", user.getUsername(), user.getEmail()), e); // errors.rejectValue("username", "errors.existing.user", // new Object[]{user.getUsername(), user.getEmail()}, // "duplicate user"); throw e; } // log user in automatically final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( user.getUsername(), user.getConfirmPassword(), user.getAuthorities()); auth.setDetails(user); SecurityContextHolder.getContext().setAuthentication(auth); // Send user an e-mail if (log.isDebugEnabled()) { log.debug("Sending user '" + user.getUsername() + "' an account information e-mail"); } // Send an account information e-mail final Locale locale = LocaleContextHolder.getLocale(); message.setSubject(getText("signup.email.subject", locale)); try { sendUserMessage(user, "accountCreated.vm", getText("signup.email.message", locale), RequestUtil.getAppURL(getServletRequest())); } catch (final MailException me) { // saveError(request, me.getMostSpecificCause().getMessage()); throw me; } return user; } /** * * @return */ @Override public User editProfile() { final String username = getCurrentUsername(); final User user = userManager.getUserByUsername(username); user.setConfirmPassword(user.getPassword()); return user; } /** * * @param user * @return * @throws Exception */ @Override public User editProfile(final User user) throws Exception { final String username = getCurrentUsername(); if (!username.equals(user.getUsername())) { throw new AccessDeniedException("Trying to edit another users profile"); } return userManager.saveUser(user); } /** * * @param userId * @return */ @Override public User getUser(final Long userId) { final User user = userManager.get(userId); user.setConfirmPassword(user.getPassword()); return user; } /** * * @param user * @return * @throws Exception */ @Override public User saveUser(final User user) throws Exception { if (user.getVersion() == null && user.getPassword() == null) { final int length = RandomUtils.nextInt(8) + 8; user.setPassword(RandomStringUtils.randomAlphanumeric(length)); } return userManager.saveUser(user); } /** * * @param searchCriteria * @return */ @Override public long countUsers(final UsersSearchCriteria searchCriteria) { final String searchTerm = searchCriteria != null ? searchCriteria.getSearchTerm() : null; return userManager.search(searchTerm).size(); } /** * * @param searchCriteria * @param firstResult * @param maxResults * @return */ @Override public List<User> searchUsers(final UsersSearchCriteria searchCriteria, final int firstResult, final int maxResults) { return searchUsers(searchCriteria, firstResult, maxResults, null, true); } /** * * @param searchCriteria * @param firstResult * @param maxResults * @return */ @Override public List<User> searchUsers(final UsersSearchCriteria searchCriteria, final int firstResult, final int maxResults, final String sortProperty, final boolean ascending) { final String searchTerm = searchCriteria != null ? searchCriteria.getSearchTerm() : null; final List<User> users = userManager.search(searchTerm); if (StringUtils.isNotEmpty(sortProperty)) { log.debug(String.format("Sorting usersList by property='%s', ascending='%s'", sortProperty, ascending)); Collections.sort(users, new PropertyComparator(sortProperty, true, ascending)); } final int fromIndex = Math.min(firstResult, users.size()); final int toIndex = Math.min(fromIndex + maxResults, users.size()); log.debug(String.format("searchUsers(%d,%d) %d-%d [%d]", firstResult, maxResults, fromIndex, toIndex, users.size())); return users.subList(fromIndex, toIndex); } /** * * @param user */ @Override public void removeUser(final Long userId) { userManager.removeUser(userId.toString()); } /** * * @param username * @return */ @Override public String sendPasswordHint(final String username) { final Locale locale = LocaleContextHolder.getLocale(); // ensure that the username has been sent if (username == null) { log.warn("Username not specified, notifying user that it's a required field."); return null; } log.debug("Processing Password Hint..."); // look up the user's information try { final User user = userManager.getUserByUsername(username); final StringBuffer msg = new StringBuffer(); msg.append("Your password hint is: ").append(user.getPasswordHint()); msg.append("\n\nLogin at: ").append(RequestUtil.getAppURL(getServletRequest())); message.setTo(user.getEmail()); final String subject = '[' + getText("webapp.name", locale) + "] " + getText("user.passwordHint", locale); message.setSubject(subject); message.setText(msg.toString()); mailEngine.send(message); return user.getFullName();// XXX disabling returning // user.getEmail(); } catch (final UsernameNotFoundException e) { log.warn(e.getMessage()); } catch (final MailException me) { log.warn(me.getMessage()); } return null; } /** * * @param username * @return */ @Override public String requestRecoveryToken(final String username) { final Locale locale = LocaleContextHolder.getLocale(); log.debug("Sending recovery token to user " + username); try { userManager.sendPasswordRecoveryEmail(username, RequestUtil.getAppURL(getServletRequest()) + RECOVERY_PASSWORD_TEMPLATE); } catch (final UsernameNotFoundException ignored) { // lets ignore this } return getText("updatePassword.recoveryToken.sent", locale); } /** * * @param username * @param token * @param currentPassword * @param password * @return * @throws UserExistsException */ @Override public User updatePassword( final String username, final String token, final String currentPassword, final String password) throws UserExistsException { final HttpServletRequest request = getServletRequest(); if (StringUtils.isEmpty(password)) { return null; } User user = null; final boolean usingToken = StringUtils.isNotBlank(token); if (usingToken) { log.debug("Updating Password for username " + username + ", using reset token"); user = userManager.updatePassword(username, null, token, password, RequestUtil.getAppURL(request)); } else { log.debug("Updating Password for username " + username + ", using current password"); if (!username.equals(getCurrentUser().getUsername())) { throw new AccessDeniedException("You do not have permission to modify other users password."); } user = userManager.updatePassword(username, currentPassword, null, password, RequestUtil.getAppURL(request)); } return user; } /** * * @return */ @Override public List<User> getActiveUsers() { return new ArrayList((Set) getServletContext().getAttribute(UserCounterListener.USERS_KEY)); } /** * */ @Override public boolean logout() { final HttpServletRequest request = getServletRequest(); final HttpServletResponse response = getServletResponse(); if (request.getSession(false) != null) { request.getSession(false).invalidate(); } final Cookie terminate = new Cookie(TokenBasedRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, null); final String contextPath = request.getContextPath(); terminate.setPath(contextPath != null && contextPath.length() > 0 ? contextPath : "/"); terminate.setMaxAge(0); response.addCookie(terminate); return true; } }