Java tutorial
/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.opentides.service.impl; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.RandomStringUtils; import org.apache.log4j.Logger; import org.opentides.bean.user.BaseUser; import org.opentides.bean.user.PasswordReset; import org.opentides.bean.user.SessionUser; import org.opentides.bean.user.UserCredential; import org.opentides.bean.user.UserGroup; import org.opentides.dao.PasswordResetDao; import org.opentides.dao.UserDao; import org.opentides.dao.UserGroupDao; import org.opentides.dao.impl.AuditLogDaoImpl; import org.opentides.exception.InvalidImplementationException; import org.opentides.service.MailingService; import org.opentides.service.UserGroupService; import org.opentides.service.UserService; import org.opentides.util.SecurityUtil; import org.opentides.util.StringUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.core.Authentication; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.stereotype.Service; @Service(value = "userService") public class UserServiceImpl extends BaseCrudServiceImpl<BaseUser> implements UserService { private static final Logger _log = Logger.getLogger(UserServiceImpl.class); @Autowired private MailingService mailingService; @Autowired private UserGroupService userGroupService; @Autowired private PasswordResetDao passwordResetDao; @Autowired private UserGroupDao userGroupDao; @Autowired private SessionRegistry sessionRegistry; @Autowired @Qualifier("passwordEncoder") private PasswordEncoder passwordEncoder; private int tokenLength = 10; @Value("#{applicationSettings['confirm.password.reset.url']}") private String confirmURL; @Autowired public void setUserDao(UserDao userDao) { this.dao = userDao; } /** Static helper that encrypts the given password * into its appropriate encryption settings. * @param cleartext * @return */ public String encryptPassword(String cleartext) { if (passwordEncoder != null) { return passwordEncoder.encode(cleartext); } else return cleartext; } /** * Ensures that admin user is created into the database. This method is * called by ApplicationStartupListener to ensure admin user is available */ public boolean setupAdminUser() { boolean exist = false; // let's check if there are users in the database UserDao userDao = (UserDao) getDao(); if (userDao.countAll() > 0) { exist = true; } else { // if none, let's create admin user BaseUser user = new BaseUser(); UserCredential cred = new UserCredential(); cred.setUsername("admin"); cred.setPassword(encryptPassword("ideyatech")); cred.setEnabled(true); cred.setUser(user); user.setCredential(cred); user.setEmailAddress("admin@opentides.com"); user.setFirstName("Administrator"); user.setLastName("Administrator"); UserGroup userGroup = userGroupDao.loadUserGroupByName("Administrator"); user.addGroup(userGroup); userDao.saveEntityModel(user); _log.info("New installation detected, inserted admin/opentides user to database."); } return !exist; } /** * Updates last login of the user from a login event. Also logs the event in * history log. */ public void updateLogin(AuthenticationSuccessEvent authenticationSuccessEvent) { UserDao userDao = (UserDao) getDao(); String username = authenticationSuccessEvent.getAuthentication().getName(); if (username != null && !username.isEmpty()) { BaseUser user = userDao.loadByUsername(username); WebAuthenticationDetails details = (WebAuthenticationDetails) authenticationSuccessEvent .getAuthentication().getDetails(); if (details != null) { String address = details.getRemoteAddress(); if (user.getTotalLoginCount() == null) user.setTotalLoginCount(1l); else user.setTotalLoginCount(user.getTotalLoginCount() + 1); user.setPrevLoginIP(user.getLastLoginIP()); user.setLastLoginIP(address); user.setLastLogin(new Date()); user.setSkipAudit(true); userDao.saveEntityModel(user); // force the audit user details String completeName = user.getCompleteName() + " [" + username + "] "; user.setAuditUserId(user.getId()); user.setAuditUsername(username); user.setSkipAudit(false); String message = completeName + " has logged-in. IP Address: " + user.getLastLoginIP(); AuditLogDaoImpl.logEvent(message, user); } } } /** * Records the logout event and save to history log for audit tracking * purposes. */ @Override public void updateLogout(Authentication auth) { if (auth == null) return; Object userObj = auth.getPrincipal(); if (userObj instanceof SessionUser) { SessionUser sessionUser = (SessionUser) userObj; String username = sessionUser.getUsername(); UserDao userDao = (UserDao) getDao(); // also add log to audit history log BaseUser user = userDao.loadByUsername(username); String completeName = user.getCompleteName() + " [" + username + "] "; // force the audit user details user.setAuditUserId(user.getId()); user.setAuditUsername(username); String message = completeName + " has logged-out. IP Address: " + user.getLastLoginIP(); AuditLogDaoImpl.logEvent(message, user); } } /** * Returns the list of user session that is logged-in to the system. * * @return */ public List<SessionInformation> getAllLoggedUsers() { List<SessionInformation> results = new ArrayList<SessionInformation>(); for (Object prince : sessionRegistry.getAllPrincipals()) { for (SessionInformation si : sessionRegistry.getAllSessions(prince, false)) { results.add(si); } } return results; } /* * (non-Javadoc) * * @see com.ideyatech.core.service.UserService#forceLogout(java.lang.String) */ public void forceLogout(String username) { // let's logout all sessions of this user for (Object prince : sessionRegistry.getAllPrincipals()) { if (prince instanceof SessionUser) { SessionUser user = (SessionUser) prince; if (user.getUsername().equals(username)) { for (SessionInformation si : sessionRegistry.getAllSessions(prince, false)) { si.expireNow(); } } } } } @Override public boolean isUserLockedOut(String username, long maxAttempts, long lockOutTime) { UserDao userDao = (UserDao) getDao(); BaseUser user = userDao.loadByUsername(username); if (user != null) { if (user.getFailedLoginCount() != null && user.getFailedLoginCount() >= maxAttempts) { long elapsedTime = System.currentTimeMillis() - (user.getLastFailedLoginMillis() == null ? 0 : user.getLastFailedLoginMillis()); if (elapsedTime < 1000 * lockOutTime) { return true; } } } return false; } @Override public void unlockUser(String username) { UserDao userDao = (UserDao) getDao(); BaseUser user = userDao.loadByUsername(username); user.resetFailedLoginCount(); userDao.saveEntityModel(user); } @Override public void updateFailedLogin(String username, long timestamp) { UserDao userDao = (UserDao) getDao(); BaseUser user = userDao.loadByUsername(username); if (user != null) { user.incrementFailedLoginCount(); user.setLastFailedLoginMillis(timestamp); userDao.saveEntityModel(user); } } @Override public List<BaseUser> findUsersLikeLastName(String name, int maxResults) { return getUserDao().findUsersLikeLastName(name, -1, maxResults); } public BaseUser getCurrentUser() { try { SessionUser sessionUser = SecurityUtil.getSessionUser(); UserDao userDao = (UserDao) getDao(); if (sessionUser != null) return userDao.loadByUsername(sessionUser.getUsername()); else return null; } catch (Exception e) { return null; } } @Override public void registerUser(BaseUser baseUser, boolean sendEmail) { //TODO enable user (should be disabled by default) baseUser.getCredential().setEnabled(true); //encrypt password UserCredential credential = baseUser.getCredential(); if (!StringUtil.isEmpty(credential.getNewPassword())) credential.setPassword(encryptPassword(credential.getNewPassword())); baseUser.setCredential(credential); save(baseUser); if (sendEmail) { //send verification email Map<String, Object> templateVariables = new HashMap<String, Object>(); templateVariables.put("name", baseUser.getCompleteName()); templateVariables.put("activationLink", "http://www.google.com"); mailingService.sendEmail(new String[] { baseUser.getEmailAddress() }, "Verify your Email Address", "email-verification.vm", templateVariables); } } @Override public UserCredential generateFakeCredentials() { UserDao userDao = (UserDao) getDao(); UserCredential credential = new UserCredential(); String username; do { username = RandomStringUtils.randomAlphanumeric(10); } while (userDao.loadByUsername(username) != null); credential.setSkipAudit(true); credential.setEnabled(Boolean.TRUE); credential.setUsername(username); credential.setPassword(encryptPassword(RandomStringUtils.randomAlphanumeric(10))); return credential; } @Override public List<BaseUser> findAllUsersWithAuthority(String authority) { return getUserDao().findAllUsersWithAuthority(authority); } private UserDao getUserDao() { return (UserDao) this.dao; } @Override public void requestPasswordReset(String emailAddress) { UserDao userDAO = (UserDao) getDao(); if (!userDAO.isRegisteredByEmail(emailAddress)) { throw new InvalidImplementationException("Email [" + emailAddress + "] was not validated prior to calling this service. Please validate first."); } PasswordReset passwd = new PasswordReset(); String token = StringUtil.generateRandomString(tokenLength); String cipher = StringUtil.encrypt(token + emailAddress); passwd.setEmailAddress(emailAddress); passwd.setToken(token); passwd.setStatus("active"); passwd.setCipher(cipher); passwordResetDao.saveEntityModel(passwd); // send email for confirmation sendEmailConfirmation(emailAddress, token, cipher); } /** * @param emailAddress * @param token * @param cipher */ private void sendEmailConfirmation(String emailAddress, String token, String cipher) { Map<String, Object> dataMap = new HashMap<String, Object>(); dataMap.put("address", emailAddress); dataMap.put("confirmationCode", token); dataMap.put("confirmURL", confirmURL); dataMap.put("link", confirmURL + "?cipher=" + cipher); mailingService.sendEmail(new String[] { emailAddress }, "Information regarding your password reset", "password_reset.vm", dataMap); } /** * Resets the password by specifying email address and token. */ public boolean confirmPasswordReset(String emailAddress, String token) { // check if email and token matched PasswordReset example = new PasswordReset(); example.setEmailAddress(emailAddress); example.setToken(token); example.setStatus("active"); List<PasswordReset> actuals = passwordResetDao.findByExample(example, true); if (actuals == null || actuals.size() == 0) { _log.info("Failed to confirm password reset. No records matched in password reset database for email " + emailAddress); return false; } // check if password reset is active and not expired PasswordReset actual = actuals.get(0); Date updated = actual.getUpdateDate(); Date expireDate = new Date(updated.getTime() + 86400000); Date today = new Date(); if (expireDate.getTime() < today.getTime()) { // expired _log.info("Password reset has expired for " + emailAddress); actual.setStatus(PasswordReset.STATUS_EXPIRED); passwordResetDao.saveEntityModel(actual); return false; } return true; } /** * Validates the cipher for password reset and returns the corresponding * email address and token. * * @param passwd * @return */ @Override public boolean confirmPasswordResetByCipher(PasswordReset passwd) { String decrypted = ""; try { decrypted = StringUtil.decrypt(passwd.getCipher()); } catch (Exception e) { _log.error("Failed to decrypt password.", e); } if (StringUtil.isEmpty(decrypted)) { _log.info("Failed attempt to confirm password reset due to wrong cipher key.[" + passwd.getCipher() + "]"); return false; } String token = decrypted.substring(0, tokenLength); String email = decrypted.substring(tokenLength); passwd.setToken(token); passwd.setEmailAddress(email); return confirmPasswordReset(email, token); } /** * Resets the password * * @param passwd * @return */ @Override public boolean resetPassword(PasswordReset passwd) { // check if password reset is active and not expired PasswordReset example = new PasswordReset(); example.setEmailAddress(passwd.getEmailAddress()); example.setToken(passwd.getToken()); example.setStatus("active"); List<PasswordReset> actuals = passwordResetDao.findByExample(example, true); if (actuals == null || actuals.size() == 0) { _log.info("Failed to reset password. No records found in password reset for email " + passwd.getEmailAddress()); return false; } PasswordReset actual = actuals.get(0); actual.setStatus(PasswordReset.STATUS_USED); passwordResetDao.saveEntityModel(actual); // now reset the password UserDao userDAO = (UserDao) getDao(); BaseUser user = userDAO.loadByEmailAddress(passwd.getEmailAddress()); user.getCredential().setPassword(encryptPassword(passwd.getPassword())); userDAO.saveEntityModel(user); return true; } @Override public List<SessionInformation> getAllLoggedUsersPagenation(int start, int total) { List<SessionInformation> results = new ArrayList<SessionInformation>(); for (Object prince : sessionRegistry.getAllPrincipals()) { for (SessionInformation si : sessionRegistry.getAllSessions(prince, false)) { results.add(si); } } if (results.size() > total) { return results.subList(start, total); } return results; } }