/*
* (c) 2008- RANDI2 Core Development Team
*
* This file is part of RANDI2.
*
* RANDI2 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 3 of the License, or (at your option) any later
* version.
*
* RANDI2 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
* RANDI2. If not, see <http://www.gnu.org/licenses/>.
*/
package de.randi2.services;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import de.randi2.dao.LoginDao;
import de.randi2.dao.RoleDao;
import de.randi2.dao.TrialSiteDao;
import de.randi2.model.Login;
import de.randi2.model.Person;
import de.randi2.model.Role;
import de.randi2.model.TrialSite;
import de.randi2.utility.mail.MailServiceInterface;
import de.randi2.utility.mail.exceptions.MailErrorException;
import de.randi2.utility.security.RolesAndRights;
/**
*
* @author dschrimpf
*
*/
@Service("userService")
public class UserServiceImpl implements UserService {
private Logger logger = Logger.getLogger(UserServiceImpl.class);
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ReflectionSaltSource saltSourceUser;
@Autowired
private LoginDao loginDao;
@Autowired
private TrialSiteDao trialSiteDao;
@Autowired
private RoleDao roleDao;
@Autowired
private MailServiceInterface mailService;
@Autowired
private RolesAndRights rolesAndRights;
@Override
@Transactional(propagation = Propagation.SUPPORTS)
@Secured({ "ROLE_USER", "AFTER_ACL_READ" })
public Login getUser(String username) {
return loginDao.get(username);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createRole(Role newRole) {
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " create new role " + newRole.getName());
roleDao.create(newRole);
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteRole(Role oldRole) {
// TODO Auto-generated method stub
throw new RuntimeException("not yet implemented");
}
@Override
public Login prepareInvestigator() {
Login newUser = new Login();
newUser.setPerson(new Person());
newUser.addRole(Role.ROLE_ANONYMOUS);
AnonymousAuthenticationToken authToken = new AnonymousAuthenticationToken(
"anonymousUser", newUser, new ArrayList<GrantedAuthority>(
newUser.getAuthorities()));
// Perform authentication
SecurityContextHolder.getContext().setAuthentication(authToken);
SecurityContextHolder.getContext().getAuthentication()
.setAuthenticated(true);
return newUser;
}
@Override
@Secured({ "ROLE_ANONYMOUS", "ACL_LOGIN_CREATE" })
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void register(Login newObject, TrialSite site) {
logger.info("register new user with username/eMail "
+ newObject.getUsername() +" and the trial site: "+ site.getName());
site = trialSiteDao.refresh(site);
// Investigator Role (self-registration process)
if (newObject.getRoles().size() == 1
&& newObject.getRoles().iterator().next()
.equals(Role.ROLE_ANONYMOUS)) {
newObject.addRole(Role.ROLE_INVESTIGATOR);
}
newObject.setPassword(passwordEncoder.encodePassword(
newObject.getPassword(), saltSourceUser.getSalt(newObject)));
loginDao.create(newObject);
site.getMembers().add(newObject.getPerson());
trialSiteDao.update(site);
// send registration Mail
sendRegistrationMail(newObject);
}
/*
* (non-Javadoc)
*
* @see de.randi2.services.UserService#create(de.randi2.model.Login)
*/
@Override
@Secured({ "ACL_LOGIN_CREATE" })
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void create(Login newObject, TrialSite site) {
site = trialSiteDao.refresh(site);
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " create new user "
+ newObject.getUsername());
newObject.setPassword(passwordEncoder.encodePassword(
newObject.getPassword(), saltSourceUser.getSalt(newObject)));
loginDao.create(newObject);
site.getMembers().add(newObject.getPerson());
site = trialSiteDao.update(site);
// send registration Mail
sendRegistrationMail(newObject);
}
@Override
@Secured({ "ACL_LOGIN_WRITE" })
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Login update(Login changedObject) {
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " update user "
+ changedObject.getUsername());
if (changedObject.getPassword().length() != 64) {
changedObject.setPassword(passwordEncoder.encodePassword(
changedObject.getPassword(),
saltSourceUser.getSalt(changedObject)));
}
addAndRemoveRoles(changedObject);
return loginDao.update(changedObject);
}
@Transactional(propagation = Propagation.REQUIRED)
private void addAndRemoveRoles(Login changedObject){
//check roles
Login oldLogin = loginDao.get(changedObject.getId());
List<Role> removedRoles = new ArrayList<Role>();
List<Role> addedRoles = new ArrayList<Role>();
if(!(oldLogin.getRoles().containsAll(changedObject.getRoles()) && changedObject.getRoles().containsAll(oldLogin.getRoles()))){
//identify removed roles
for(Role r : oldLogin.getRoles()){
if(!changedObject.getRoles().contains(r)){
removedRoles.add(r);
}
}
//identify added roles
for(Role r : changedObject.getRoles()){
if(!oldLogin.getRoles().contains(r)){
addedRoles.add(r);
}
}
}
for(Role r: addedRoles){
rolesAndRights.registerPersonRole(changedObject, r);
}
for(Role r: removedRoles){
rolesAndRights.removedPersonRole(changedObject, r);
}
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Role updateRole(Role changedRole) {
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " update role " + changedRole.getName()
+ " (id=" + changedRole.getId() + ")");
return roleDao.update(changedRole);
}
@Override
@Secured({ "ROLE_USER", "AFTER_ACL_COLLECTION_READ" })
@Transactional(propagation = Propagation.SUPPORTS)
public List<Login> getAll() {
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " get all users");
return loginDao.getAll();
}
@Override
@Secured({ "ROLE_USER", "AFTER_ACL_READ" })
@Transactional(propagation = Propagation.SUPPORTS)
public Login getObject(long objectID) {
logger.info("user: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName() + " get login with id=" + objectID);
return loginDao.get(objectID);
}
private void sendRegistrationMail(Login newUser) {
// Map of variables for the message
Map<String, Object> newUserMessageFields = new HashMap<String, Object>();
newUserMessageFields.put("user", newUser);
// Map of variables for the subject
Map<String, Object> newUserSubjectFields = new HashMap<String, Object>();
newUserSubjectFields.put("firstname", newUser.getPerson()
.getFirstname());
Locale language = newUser.getPrefLocale();
try {
mailService.sendMail(newUser.getPerson().getEmail(), "NewUserMail",
language, newUserMessageFields, newUserSubjectFields);
} catch (MailErrorException e) {
logger.error("Mail error", e);
}
TrialSite trialSiteOfNewPerson = trialSiteDao.get(newUser.getPerson());
if (trialSiteOfNewPerson != null
&& trialSiteOfNewPerson.getContactPerson() != null) {
// send e-mail to contact person of current trial-site
Person contactPerson = trialSiteOfNewPerson
.getContactPerson();
language = Locale.getDefault();
// Map of variables for the message
Map<String, Object> contactPersonMessageFields = new HashMap<String, Object>();
contactPersonMessageFields.put("newUser", newUser);
contactPersonMessageFields.put("contactPerson", contactPerson);
// Map of variables for the subject
Map<String, Object> contactPersonSubjectFields = new HashMap<String, Object>();
contactPersonSubjectFields.put("newUserFirstname", newUser
.getPerson().getFirstname());
contactPersonSubjectFields.put("newUserLastname", newUser
.getPerson().getSurname());
contactPersonSubjectFields.put("trialSite", trialSiteOfNewPerson.getName());
try {
mailService.sendMail(contactPerson.getEmail(),
"NewUserNotifyContactPersonMail", language,
contactPersonMessageFields, contactPersonSubjectFields);
} catch (MailErrorException e) {
logger.error("Mail error", e);
}
}
}
@Override
@Secured({ "ROLE_USER" })
@Transactional(propagation = Propagation.SUPPORTS)
public List<Role> getAllRoles() {
return roleDao.getAll();
}
@Override
@Secured({ "ROLE_USER" })
@Transactional(propagation = Propagation.SUPPORTS)
public Role getRole(String name) {
return roleDao.get(name);
}
@Override
@Secured({ "ROLE_USER" })
@Transactional(propagation = Propagation.SUPPORTS)
public Set<Role> getRolesToAssign(Login login) {
login = loginDao.refresh(login);
Set<Role> rolesToAssign = new HashSet<Role>();
for(Role role : login.getRoles()){
rolesToAssign.addAll(role.getRolesToAssign());
}
return rolesToAssign;
}
}