/*
* Copyright 2009-2010 the original author or authors.
*
* Licensed 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.internna.iwebmvc.spring.services.dwr;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collection;
import javax.annotation.security.RolesAllowed;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;
import org.internna.iwebmvc.dao.SecurityDAO;
import org.internna.iwebmvc.model.Role;
import org.internna.iwebmvc.model.User;
import org.internna.iwebmvc.model.security.UserImpl;
import org.internna.iwebmvc.utils.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import static org.internna.iwebmvc.utils.StringUtils.hasText;
/**
* Remoted service that controls user security.
*
* @author Jose Noheda
* @since 2.0
*/
@RemoteProxy(name = "UserEditor")
public class UserEditorImpl implements UserEditor {
private String salt;
private SecurityDAO dao;
/**
* Spring injection point.
*
* @param dao a non null instance
*/
@Required public final void setDao(SecurityDAO dao) {
Assert.notNull(dao);
this.dao = dao;
}
/**
* Spring required injection point. Sets the server salt for passwords.
*
* @param salt a non null string
*/
@Required public void setSalt(String salt) {
Assert.hasText(salt);
this.salt = salt;
}
@RemoteMethod
@Transactional
@RolesAllowed("ROLE_SECURITY_MANAGER")
@Override public void changePassword(String username, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
if (hasText(username) && hasText(password)) {
UserImpl user = (UserImpl) dao.findUser(username);
if (user != null) {
user.setSalt(salt);
user.setPassword(password);
dao.updateUser(user);
}
}
}
@RemoteMethod
@Transactional
@RolesAllowed("ROLE_SECURITY_MANAGER")
@Override public void saveOrUpdate(User user, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
if (user != null) {
User existing = dao.findUser(user.getUsername());
if (existing == null) createNewUser(user, password);
else updateUser(user, existing);
}
}
private void createNewUser(User user, String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
Collection <Role> roles = new HashSet<Role>();
for (Role role : user.getRoles()) roles.add(role);
user.clearRoles();
if (user instanceof UserImpl) {
UserImpl impl = (UserImpl) user;
impl.setPassword(password);
}
dao.createUser(user);
updateAuthorities(user, roles);
}
private void updateUser(User user, User existing) {
BeanUtils.copyProperties(user, existing, new String[] {"username", "password", "roles"});
dao.updateUser(existing);
updateAuthorities(existing, user.getRoles());
}
private void updateAuthorities(User user, Collection<? extends Role> roles) {
if (!CollectionUtils.isEmpty(roles)) {
for (Role role : roles) {
Role authority = dao.findAuthority(role.getRole());
if (authority != null) {
if ((user.getRoles() == null) || (!user.getRoles().contains(authority))) {
user.addRole(authority);
authority.addMember(user);
}
}
}
}
if (!CollectionUtils.isEmpty(user.getRoles())) {
for (Iterator<? extends Role> it = user.getRoles().iterator(); it.hasNext();) {
Role role = it.next();
if (!roles.contains(role)) {
it.remove();
role.removeMember(user);
}
}
}
dao.updateUser(user);
if (!CollectionUtils.isEmpty(user.getRoles()))
for (Role role : user.getRoles())
dao.updateAuthority(role);
}
private String parseNull(String field) {
return hasText(field) ? field + "%" : null;
}
@Override
@RemoteMethod
@Transactional
@RolesAllowed("ROLE_SECURITY_MANAGER")
public List<User> fetch(String usernameFilter, String nameFilter, String roleFilter, int offset, int number) {
return dao.findUsers(parseNull(usernameFilter), parseNull(nameFilter), roleFilter, offset, number);
}
@RemoteMethod
@Transactional
@RolesAllowed("ROLE_SECURITY_MANAGER")
@Override public void toggleUser(String username) {
User existing = dao.findUser(username);
if (existing != null) {
existing.toggle();
dao.updateUser(existing);
}
}
}