Java tutorial
/* Copyright 2008-2012 Josh Drummond This file is part of WebPasswordSafe. WebPasswordSafe 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 2 of the License, or (at your option) any later version. WebPasswordSafe 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 WebPasswordSafe; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.webpasswordsafe.server.service; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.Resource; import net.webpasswordsafe.client.remote.LoginService; import net.webpasswordsafe.client.remote.PasswordService; import net.webpasswordsafe.common.model.AccessLevel; import net.webpasswordsafe.common.model.Password; import net.webpasswordsafe.common.model.PasswordAccessAudit; import net.webpasswordsafe.common.model.PasswordData; import net.webpasswordsafe.common.model.Permission; import net.webpasswordsafe.common.model.Tag; import net.webpasswordsafe.common.model.Template; import net.webpasswordsafe.common.model.TemplateDetail; import net.webpasswordsafe.common.model.User; import net.webpasswordsafe.common.util.Constants.Match; import net.webpasswordsafe.common.util.Utils; import net.webpasswordsafe.common.util.Constants.Function; import net.webpasswordsafe.server.ServerSessionUtil; import net.webpasswordsafe.server.dao.PasswordAccessAuditDAO; import net.webpasswordsafe.server.dao.PasswordDAO; import net.webpasswordsafe.server.dao.TagDAO; import net.webpasswordsafe.server.dao.TemplateDAO; import net.webpasswordsafe.server.plugin.audit.AuditLogger; import net.webpasswordsafe.server.plugin.authorization.Authorizer; import net.webpasswordsafe.server.plugin.encryption.Encryptor; import net.webpasswordsafe.server.plugin.generator.PasswordGenerator; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.google.gwt.user.server.rpc.XsrfProtectedServiceServlet; /** * Implementation of Password Service * * @author Josh Drummond * */ @Service("passwordService") public class PasswordServiceImpl extends XsrfProtectedServiceServlet implements PasswordService { private static final long serialVersionUID = -2328314230839034189L; private static Logger LOG = Logger.getLogger(PasswordServiceImpl.class); @Autowired private PasswordDAO passwordDAO; @Autowired private TagDAO tagDAO; @Autowired private PasswordAccessAuditDAO passwordAccessAuditDAO; @Autowired private TemplateDAO templateDAO; @Resource private PasswordGenerator passwordGenerator; @Autowired private LoginService loginService; @Resource private Encryptor encryptor; @Resource private AuditLogger auditLogger; @Resource private Authorizer authorizer; @Override @Transactional(propagation = Propagation.REQUIRED) public void addPassword(Password password) { Date now = new Date(); String action = "add password"; User loggedInUser = getLoggedInUser(); if (authorizer.isAuthorized(loggedInUser, Function.ADD_PASSWORD.name())) { if (password.getPermissions().size() > 0) { password.setUserCreated(loggedInUser); password.setDateCreated(now); password.setUserLastUpdate(loggedInUser); password.setDateLastUpdate(now); password.getCurrentPasswordData().setUserCreated(loggedInUser); password.getCurrentPasswordData().setDateCreated(now); password.getCurrentPasswordData() .setPassword(encryptor.encrypt(password.getCurrentPasswordData().getPassword())); // update tags Set<Tag> tags = new HashSet<Tag>(password.getTags()); password.removeTags(); for (Tag tag : tags) { Tag pTag = tagDAO.findTagByName(tag.getName()); if (null != pTag) { password.addTag(pTag); } else { password.addTag(tag); } } passwordDAO.makePersistent(password); auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); } else { auditLogger.log(now, ServerSessionUtil.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), false, "missing permissions"); throw new RuntimeException("Missing Permissions"); } } else { auditLogger.log(now, ServerSessionUtil.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), false, "not authorized"); throw new RuntimeException("Not Authorized!"); } } @Override @Transactional(propagation = Propagation.REQUIRED) public void updatePassword(Password updatePassword) { LOG.debug("updating password"); Date now = new Date(); String action = "update password"; User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordById(updatePassword.getId(), loggedInUser, AccessLevel.WRITE); if (password != null) { if (updatePassword.getPermissions().size() > 0) { String passwordMessage = (updatePassword.getName().equals(password.getName())) ? "" : ("was: " + passwordTarget(password)); // update simple fields password.setName(updatePassword.getName()); password.setUsername(updatePassword.getUsername()); password.setNotes(updatePassword.getNotes()); password.setDateLastUpdate(now); password.setUserLastUpdate(loggedInUser); password.setActive(updatePassword.isActive()); password.setMaxHistory(updatePassword.getMaxHistory()); // update tags password.removeTags(); for (Tag tag : updatePassword.getTags()) { Tag pTag = tagDAO.findTagByName(tag.getName()); if (null != pTag) { password.addTag(pTag); } else { password.addTag(tag); } } // update password data, push others back in history if applicable PasswordData updatePasswordData = updatePassword.getCurrentPasswordData(); String updatePasswordVal = updatePasswordData.getPassword(); // if user entered a password value and its not the same as the current one... if (!"".equals(updatePasswordVal)) { String currentPasswordVal = encryptor.decrypt(password.getCurrentPasswordData().getPassword()); if (!updatePasswordVal.equals(currentPasswordVal)) { updatePasswordData.setUserCreated(loggedInUser); updatePasswordData.setDateCreated(now); updatePasswordData.setPassword(encryptor.encrypt(updatePasswordVal)); password.addPasswordData(updatePasswordData); } } // trim history if not infinite password.pruneDataHistory(); // update permissions if allowed to grant if (passwordDAO.findAllowedPasswordById(updatePassword.getId(), loggedInUser, AccessLevel.GRANT) != null) { // keep the permissions that haven't changed password.getPermissions().retainAll(updatePassword.getPermissions()); // add the permissions that have changed for (Permission permission : updatePassword.getPermissions()) { if (permission.getId() == 0) { password.addPermission(permission); } } } else { LOG.debug("no access to grant permissions"); } auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(updatePassword), true, passwordMessage); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(updatePassword), false, "missing permissions"); throw new RuntimeException("Missing Permissions"); } } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(updatePassword), false, "write access denied"); } } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public List<Password> searchPassword(String query, boolean activeOnly, Collection<Tag> tags, Match tagMatch) { query = Utils.safeString(query); Date now = new Date(); User loggedInUser = getLoggedInUser(); List<Password> passwords = passwordDAO.findPasswordByFuzzySearch(query, loggedInUser, activeOnly, tags, tagMatch); auditLogger.log( now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), "search password", "query=[" + query + "] activeOnly=[" + activeOnly + "] tags=[" + tags + "] tagMatch=[" + tagMatch + "]", true, "found " + passwords.size()); return passwords; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public String generatePassword() { LOG.debug("generating password..."); return passwordGenerator.generatePassword(); } @Override @Transactional(propagation = Propagation.REQUIRED) public String getCurrentPassword(long passwordId) { String currentPasswordValue = ""; Date now = new Date(); String action = "get current password value"; User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordById(passwordId, loggedInUser, AccessLevel.READ); if (password != null) { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); currentPasswordValue = encryptor.decrypt(password.getCurrentPasswordData().getPassword()); createPasswordAccessAuditEntry(password, loggedInUser); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(passwordId), false, "invalid id or no access"); } return currentPasswordValue; } @Transactional(propagation = Propagation.REQUIRED) private void createPasswordAccessAuditEntry(Password password, User user) { LOG.debug("creating access audit entry for password=[" + password.getName() + "] user=[" + user.getName() + "]"); PasswordAccessAudit passwordAccessAudit = new PasswordAccessAudit(); passwordAccessAudit.setDateAccessed(new Date()); passwordAccessAudit.setPassword(password); passwordAccessAudit.setUser(user); passwordAccessAuditDAO.makePersistent(passwordAccessAudit); } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public Password getPassword(long passwordId) { Date now = new Date(); String action = "get password"; User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordById(passwordId, loggedInUser, AccessLevel.READ); if (password != null) { password.setMaxEffectiveAccessLevel(passwordDAO.getMaxEffectiveAccessLevel(password, loggedInUser)); auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(passwordId), false, "invalid id or no access"); } return password; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public Password getPassword(String passwordName) { Date now = new Date(); String action = "get password"; User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordByName(passwordName, loggedInUser, AccessLevel.READ); if (password != null) { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordName, false, "invalid name or no access"); } return password; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public List<PasswordAccessAudit> getPasswordAccessAuditData(long passwordId) { Date now = new Date(); String action = "get password access audit data"; List<PasswordAccessAudit> accessAuditList = new ArrayList<PasswordAccessAudit>(0); User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordById(passwordId, loggedInUser, AccessLevel.READ); if (null != password) { accessAuditList = passwordAccessAuditDAO.findAccessAuditByPassword(password); auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(passwordId), false, "invalid id or no access"); } LOG.debug("found " + accessAuditList.size() + " password access audit entries"); return accessAuditList; } @Override @Transactional(propagation = Propagation.REQUIRED) public List<PasswordData> getPasswordHistoryData(long passwordId) { Date now = new Date(); String action = "get password history data"; List<PasswordData> decryptedPasswordDataList = new ArrayList<PasswordData>(0); User loggedInUser = getLoggedInUser(); Password password = passwordDAO.findAllowedPasswordById(passwordId, loggedInUser, AccessLevel.READ); if (null != password) { decryptedPasswordDataList = new ArrayList<PasswordData>(password.getPasswordData().size()); for (PasswordData passwordData : password.getPasswordData()) { decryptedPasswordDataList.add(new PasswordData(encryptor.decrypt(passwordData.getPassword()), passwordData.getDateCreated(), passwordData.getUserCreated())); } createPasswordAccessAuditEntry(password, loggedInUser); auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(password), true, ""); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, passwordTarget(passwordId), false, "invalid id or no access"); } LOG.debug("found " + decryptedPasswordDataList.size() + " password history values"); return decryptedPasswordDataList; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public List<Tag> getAvailableTags() { List<Tag> tags = tagDAO.findTagsInUse(); LOG.debug("found " + tags.size() + " tags in use"); return tags; } @Override @Transactional(propagation = Propagation.REQUIRED) public void addTemplate(Template template) { Date now = new Date(); String action = "add template"; User loggedInUser = getLoggedInUser(); template.setUser(loggedInUser); templateDAO.makePersistent(template); auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, templateTarget(template), true, ""); } @Override @Transactional(propagation = Propagation.REQUIRED) public void updateTemplate(Template updateTemplate) { LOG.debug("updating template"); Date now = new Date(); String action = "update template"; User loggedInUser = getLoggedInUser(); Template template = templateDAO.findUpdatableTemplateById(updateTemplate.getId(), loggedInUser); if (template != null) { String templateMessage = (updateTemplate.getName().equals(template.getName())) ? "" : ("was: " + templateTarget(template)); // update simple fields template.setName(updateTemplate.getName()); // only change sharing status if original owner is updating or special bypass authz if ((template.getUser().getId() == loggedInUser.getId()) || authorizer.isAuthorized(loggedInUser, Function.BYPASS_TEMPLATE_SHARING.name())) { template.setShared(updateTemplate.isShared()); } // update details // keep the permissions that haven't changed template.getTemplateDetails().retainAll(updateTemplate.getTemplateDetails()); // add the permissions that have changed for (TemplateDetail templateDetail : updateTemplate.getTemplateDetails()) { if (templateDetail.getId() == 0) { template.addDetail(templateDetail); } } auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, templateTarget(updateTemplate), true, templateMessage); } else { auditLogger.log(now, loggedInUser.getUsername(), ServerSessionUtil.getIP(), action, templateTarget(updateTemplate), false, "invalid id or no access"); } } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public List<Template> getTemplates(boolean includeShared) { User loggedInUser = getLoggedInUser(); return templateDAO.findTemplatesByUser(loggedInUser, includeShared); } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public Template getTemplateWithDetails(long templateId) { Template template = templateDAO.findById(templateId); if (template != null) { template.getTemplateDetails().size(); } return template; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public boolean isPasswordTaken(String passwordName, long ignorePasswordId) { boolean isPasswordTaken = false; Password password = passwordDAO.findPasswordByName(passwordName); if (password != null) { if (password.getId() != ignorePasswordId) { isPasswordTaken = true; } } return isPasswordTaken; } @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public boolean isTemplateTaken(String templateName, long ignoreTemplateId) { boolean isTemplateTaken = false; Template template = templateDAO.findTemplateByName(templateName); if (template != null) { if (template.getId() != ignoreTemplateId) { isTemplateTaken = true; } } return isTemplateTaken; } private User getLoggedInUser() { User loggedInUser = loginService.getLogin(); if (null == loggedInUser) { throw new RuntimeException("Not Logged In!"); } return loggedInUser; } private String passwordTarget(Password password) { return password.getName() + " (passwordId=" + password.getId() + ")"; } private String passwordTarget(long passwordId) { return "passwordId=" + passwordId; } private String templateTarget(Template template) { return template.getName() + " (templateId=" + template.getId() + ")"; } }