package es.uv.saic.service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.stream.Collectors; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationServiceException; 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.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Component; import es.uv.saic.SaicApplication; import es.uv.saic.shared.domain.Usuari; @Component public class AuthProvider implements AuthenticationProvider { @Autowired private UsuariService us; @Autowired private UsuarisRolService urs; private static final Logger logger = LoggerFactory.getLogger(SaicApplication.class); @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName().toLowerCase().trim(); String password = auth.getCredentials().toString(); List authorities = new ArrayList(); Usuari u = this.us.findByUsername(username); if(u != null) { u.setGranted(this.urs.isGrantedUser(u)); u.setAdmin(this.urs.isAdminUser(u)); u.setDataTest(this.urs.isDataTestUser(u)); boolean vigent = this.us.hasActiveRol(u); if(!u.getLdap() && vigent) { if (u.getUsuari().equals(username) && u.getClau().equals(password)) { logger.info("Autenticación LOCAL correcta: "+username); List ids = u.getUsuarisRols().stream().map(ur -> ur.getRol().getIdRol()).collect(Collectors.toList()); for (String permission : this.us.getPermisosRoles(ids)) { authorities.add(new SimpleGrantedAuthority("ROLE_" + permission.toUpperCase())); } UsernamePasswordAuthenticationToken authUser = new UsernamePasswordAuthenticationToken(u, password, authorities); authUser.setDetails(u); return authUser ; } else { logger.info("Error de autenticación LOCAL ["+username+"]: el usuario o la contraseña no coinciden"); throw new BadCredentialsException("Error de autenticación LOCAL ["+username+"]: el usuario o la contraseña no coinciden"); } } else if(vigent) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://ldap.uv.es/"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "uid=" + username.toLowerCase().trim() + ", dc=uv, dc=es "); env.put(Context.SECURITY_CREDENTIALS, password); try { DirContext dc = new InitialDirContext(env); String base = "dc=uv,dc=es"; String filter = "(&(uid=" + username + "))"; int state = 0; SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setReturningAttributes(new String[] { "uid" }); NamingEnumeration resultEnum = dc.search(base, filter, ctls); while (resultEnum.hasMore() && state < 2) { SearchResult result = resultEnum.next(); Attributes attrs = result.getAttributes(); if (attrs.size() != 1) { logger.info("Error de autenticación LDAP ["+username+"]: el usuario o la contraseña no coinciden"); throw new BadCredentialsException("Error de autenticación LDAP ["+username+"]: el usuario o la contraseña no coinciden"); } NamingEnumeration e = attrs.getAll(); while (e.hasMore()) { Attribute attr = (Attribute) e.next(); if (!((String) attr.get()).equals(username)) { logger.info("Error de autenticación LDAP ["+username+"]: el usuario no coincide con el devuelto por el servidor"); throw new BadCredentialsException("Error de autenticación LDAP ["+username+"]: el usuario no coincide con el devuelto por el servidor"); } } state++; } dc.close(); if (state < 1 || state > 1) { logger.info("Error de autenticación LDAP ["+username+"]: -> el servidor LDAP ha devuelto un estado incorrecto."); throw new BadCredentialsException("Error de autenticación LDAP ["+username+"]: -> el servidor LDAP ha devuelto un estado incorrecto."); } logger.info("Autenticación LDAP correcta: " + u.getUsuari()); u.setDataUltim(LocalDateTime.now()); this.us.save(u); List ids = u.getUsuarisRols().stream().map(ur -> ur.getRol().getIdRol()).collect(Collectors.toList()); for (String permission : this.us.getPermisosRoles(ids)) { authorities.add(new SimpleGrantedAuthority("ROLE_" + permission.toUpperCase())); } UsernamePasswordAuthenticationToken authUser = new UsernamePasswordAuthenticationToken(u, password, authorities); authUser.setDetails(u); return authUser ; } catch (NamingException ex) { logger.info("Error de autenticación ["+username+"]: " + ex.getMessage()); throw new AuthenticationServiceException("Error de autenticación ["+username+"]: " + ex.getMessage()); } } } throw new BadCredentialsException("Error general en el sistema de autenticación"); } @Override public boolean supports(Class auth) { return auth.equals(UsernamePasswordAuthenticationToken.class); } }