/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sapienter.jbilling.client.authentication;
import com.sapienter.jbilling.client.authentication.util.UsernameHelper;
import com.sapienter.jbilling.server.user.UserBL;
import com.sapienter.jbilling.server.user.db.UserDTO;
import com.sapienter.jbilling.server.user.permisson.db.PermissionDTO;
import com.sapienter.jbilling.server.user.permisson.db.RoleDTO;
import grails.plugins.springsecurity.SpringSecurityService;
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService;
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* An implementation of the GrailsUserDetailsService for use with the default DaoAuthenticationProvider. This
* class fetches a user from the database and builds a list of granted authorities from the users assigned
* permissions and roles.
*
* This must be used with the {@link CompanyUserAuthenticationFilter} to provide the company ID as part
* of the username to load.
*
* @author Brian Cowdery
* @since 04-10-2010
*/
public class CompanyUserDetailsService implements GrailsUserDetailsService {
// empty list of roles for use if the given credentials don't resolve to a
// usable UserDetails. Contains a single entry that does not grant any permissions.
private static final List<GrantedAuthority> NO_AUTHORITIES;
static {
NO_AUTHORITIES = new ArrayList<GrantedAuthority>(1);
NO_AUTHORITIES.add(new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE));
}
private SpringSecurityService springSecurityService;
public SpringSecurityService getSpringSecurityService() {
return springSecurityService;
}
public void setSpringSecurityService(SpringSecurityService springSecurityService) {
this.springSecurityService = springSecurityService;
}
public UserDetails loadUserByUsername(String s, boolean loadRoles)
throws UsernameNotFoundException, DataAccessException {
return loadUserByUsername(s);
}
/**
* Loads the user account and all permissions/roles for the given user name. This method does not perform
* authentication, only retrieves the {@link UserDetails} so that authentication can proceed.
*
* @param s username (principal) to retrieve
* @return found user details
* @throws UsernameNotFoundException
* @throws DataAccessException
*/
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException, DataAccessException {
// get the user for the given name
// CompanyUserAuthenticationFilter concatenates the user name with the entity id
String[] tokens = s.split(UsernameHelper.VALUE_SEPARATOR);
if (tokens.length < 2)
throw new UsernameNotFoundException("Un-supported username '" + s + "', username must contain client id.");
String username = tokens[0];
Integer entityId = Integer.valueOf(tokens[1]);
UserBL bl = new UserBL(username, entityId);
UserDTO user = bl.getEntity();
if (user == null)
throw new UsernameNotFoundException("User '" + s + "' not found", username);
// collect granted permissions and roles
// this is a bad use of generics, the UserDetails signature should be <? extends GrantedAuthority>
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (PermissionDTO permission : bl.getPermissions()) {
permission.initializeAuthority();
authorities.add(permission);
}
for (RoleDTO role : user.getRoles()) {
role.initializeAuthority();
authorities.add(role);
}
Integer mainRoleId = bl.getMainRole();
// rebuild username token with company ID from retrieved user (just to be safe).
String usernameToken = UsernameHelper.buildUsernameToken(user.getUserName(), user.getEntity().getId());
// return user details for the retrieved account
return new CompanyUserDetails(usernameToken, user.getPassword(), user.isEnabled(),
!user.isAccountExpired(), !user.isPasswordExpired(), !user.isAccountLocked(),
authorities.isEmpty() ? NO_AUTHORITIES : authorities,
user, UserBL.getLocale(user), user.getId(), mainRoleId,
user.getEntity().getId(), user.getCurrency().getId(), user.getLanguage().getId());
}
}