package nl.ipo.cds.dao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import nl.ipo.cds.domain.Gebruiker;
import nl.ipo.cds.domain.GebruikerThemaAutorisatie;
import nl.ipo.cds.domain.TypeGebruik;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
/**
* {@link AuthenticationProvider} for Spring security that uses the {@link ManagerDao} to
* provide users and roles.
*
* Adds one or more of the following roles to the resulting authentication token upon success:
* - ROLE_USER: all users have this role.
* - ROLE_SUPERUSER: superusers/admins. These users have the superuser flag set to true.
* - The constants in {@link TypeGebruik}, prefixed with ROLE_: ROLE_RAADPLEGER, ROLE_DATABEHEERDER and ROLE_VASTSTELLER.
*/
public class ManagerDaoAuthenticationProvider implements AuthenticationProvider {
private final static Logger logger = LoggerFactory.getLogger (ManagerDaoAuthenticationProvider.class);
private final ManagerDao managerDao;
/**
* Creates a {@link ManagerDaoAuthenticationProvider} by providing the DAO instance to use.
*
* @param managerDao The {@link ManagerDao} instance to use. Cannot be null.
*/
public ManagerDaoAuthenticationProvider (final ManagerDao managerDao) {
if (managerDao == null) {
throw new NullPointerException ("managerDao cannot be null");
}
this.managerDao = managerDao;
}
/**
* {@inheritDoc}
*/
@Override
public Authentication authenticate (final Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof UsernamePasswordAuthenticationToken)) {
throw new IllegalArgumentException ("Only UsernamePasswordAuthenticationToken is supported");
}
final UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
final String username = token.getName ();
final String password = (String) authentication.getCredentials();
if (username == null || username.isEmpty ()) {
logger.error ("Failed to authenticate: empty username");
throw new BadCredentialsException ("Empty username");
}
if (password == null) {
logger.error ("Failed to authenticate user " + username + ": null password was provided");
throw new BadCredentialsException ("null password was provided");
}
// Attempt to authenticate:
if (!managerDao.authenticate (username, password)) {
logger.error ("Failed to authenticate user " + username + ": bad credentials");
throw new BadCredentialsException ("Bad credentials");
}
// Create user details:
final List<GrantedAuthority> grantedAuthorities = getGrantedAuthorities (username);
logger.info ("User " + username + " successfully authenticated (" + grantedAuthorities.toString () + ")");
return new UsernamePasswordAuthenticationToken (username, password, grantedAuthorities);
}
private List<GrantedAuthority> getGrantedAuthorities (final String username) {
final Gebruiker gebruiker = managerDao.getGebruiker (username);
if (gebruiker == null) {
return Collections.<GrantedAuthority>emptyList ();
}
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority> ();
authorities.add (new SimpleGrantedAuthority ("ROLE_USER"));
final Set<TypeGebruik> typeGebruik = new HashSet<TypeGebruik> ();
if (gebruiker.isSuperuser ()) {
authorities.add (new SimpleGrantedAuthority ("ROLE_SUPERUSER"));
if (!managerDao.getBronhouderThemas ().isEmpty ()) {
typeGebruik.addAll (Arrays.asList (TypeGebruik.values ()));
}
} else {
for (final GebruikerThemaAutorisatie gta: managerDao.getGebruikerThemaAutorisatie (gebruiker)) {
for (final TypeGebruik permission: gta.getTypeGebruik ().getPermissions ()) {
typeGebruik.add (permission);
}
}
}
for (final TypeGebruik tg: typeGebruik) {
authorities.add (new SimpleGrantedAuthority ("ROLE_" + tg.toString().toUpperCase ()));
}
return Collections.unmodifiableList (authorities);
}
/**
* {@inheritDoc}
*/
@Override
public boolean supports (final Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom (authentication);
}
}