2010-03-26 54 views
13

Tengo una aplicación web, donde los usuarios deben iniciar sesión. La contraseña se almacena en un servidor LDAP. Toda la información sobre el servidor LDAP se almacena en el servidor de aplicaciones (glassfish) como recurso jndi externo. Así que mi aplicación no sin saber nada sobre el servidor LDAP y sólo consigue un LdapContext así:¿Cómo verificar la contraseña del usuario en ldap con java con LdapContext dado?

@Resource(name = "ldap/users") 
private LdapContext ctx; 

Con este contexto, es fácil cambiar o leer la información almacenada por los usuarios, pero ¿cómo puedo comprobar sus contraseñas ? Normalmente solo haría una nueva conexión para verificar la contraseña de un usuario. De esta manera:

Hashtable env = new Hashtable(); 
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial"); 

env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial"); 
env.put(Context.SECURITY_CREDENTIALS, "mysecret"); 

DirContext ctx = new InitialDirContext(env); 

Pero como no conozco estos parámetros no puedo hacer esto. Entonces, ¿cómo puedo verificar si la contraseña de un usuario es correcta con mi LdapContext? Las contraseñas se almacenan encriptadas (ssha) por lo que no puedo simplemente comparar los atributos.

Gracias Raffael

Respuesta

8

Usted debe ser capaz de obtener el entorno del contexto LDAP, clonarlo, y luego poner el principal y credenciales para el usuario que desea comprobar:

@Resource(name = "ldap/users") 
private LdapContext ldapContext; 

Hashtable environment = ldapContext.getEnvironment().clone(); 
environment.put(Context.SECURITY_PRINCIPAL, userDN); 
environment.put(Context.SECURITY_CREDENTIALS, userPassword); 

DirContext dirContext = new InitialDirContext(environment); 
17

Este es una solución que se puede utilizar para autenticar a un usuario con algo más que el DN, por ejemplo con un uid o sAMAccountName.

Los pasos para hacerlo son:

  1. Conectar con el servidor LDAP
  2. autenticarse con un usuario de servicio de los cuales sabemos el DN y las credenciales
  3. búsqueda para el usuario desea autenticar, búsqueda él con algún atributo (por ejemplo sAMAccountName)
  4. Obtener el DN del usuario que encontramos
  5. Abra otra conexión al servidor LDAP con el DN encontrado y la contraseña
  6. Si no se encuentra el usuario y autenticación obras, que están muy bien

ejemplo Código:

public static boolean performAuthentication() { 

    // service user 
    String serviceUserDN = "cn=Mister Service,ou=Users,dc=example,dc=com"; 
    String serviceUserPassword = "abc123#!$"; 

    // user to authenticate 
    String identifyingAttribute = "uid"; 
    String identifier = "maxdev"; 
    String password = "jkl987.,-"; 
    String base = "ou=Users,dc=example,dc=com"; 

    // LDAP connection info 
    String ldap = "localhost"; 
    int port = 10389; 
    String ldapUrl = "ldap://" + ldap + ":" + port; 

    // first create the service context 
    DirContext serviceCtx = null; 
    try { 
     // use the service user to authenticate 
     Properties serviceEnv = new Properties(); 
     serviceEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
     serviceEnv.put(Context.PROVIDER_URL, ldapUrl); 
     serviceEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); 
     serviceEnv.put(Context.SECURITY_PRINCIPAL, serviceUserDN); 
     serviceEnv.put(Context.SECURITY_CREDENTIALS, serviceUserPassword); 
     serviceCtx = new InitialDirContext(serviceEnv); 

     // we don't need all attributes, just let it get the identifying one 
     String[] attributeFilter = { identifyingAttribute }; 
     SearchControls sc = new SearchControls(); 
     sc.setReturningAttributes(attributeFilter); 
     sc.setSearchScope(SearchControls.SUBTREE_SCOPE); 

     // use a search filter to find only the user we want to authenticate 
     String searchFilter = "(" + identifyingAttribute + "=" + identifier + ")"; 
     NamingEnumeration<SearchResult> results = serviceCtx.search(base, searchFilter, sc); 

     if (results.hasMore()) { 
      // get the users DN (distinguishedName) from the result 
      SearchResult result = results.next(); 
      String distinguishedName = result.getNameInNamespace(); 

      // attempt another authentication, now with the user 
      Properties authEnv = new Properties(); 
      authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
      authEnv.put(Context.PROVIDER_URL, ldapUrl); 
      authEnv.put(Context.SECURITY_PRINCIPAL, distinguishedName); 
      authEnv.put(Context.SECURITY_CREDENTIALS, password); 
      new InitialDirContext(authEnv); 

      System.out.println("Authentication successful"); 
      return true; 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (serviceCtx != null) { 
      try { 
       serviceCtx.close(); 
      } catch (NamingException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    System.err.println("Authentication failed"); 
    return false; 
} 
+0

Hola Nikolay, también creo que este es el método preferido, ya que puede buscar correctamente a los usuarios por diferentes criterios. Intenté esto sin embargo y recuperar el atributo 'distinguishedName' siempre devuelve' null'. Creo que es una mejor opción para usar 'resultado.getNameInNamespace() ', ¿qué piensas? – maxdev

+0

Hola Max, gracias por refinar mi solución. Con respecto a la obtención de un DN, creo que puede depender del proveedor del servicio LDAP. En mi caso, hace 5 años, en el clásico Microsoft AD LDAP funcionó a través del atributo de extracción 'attrs.get (" distinguishedName ")'. –

1

que he hecho en mi misma aplicación. siguiente es el que puede ser útil para usted.

package com.agileinfotech.bsviewer.servlet; 

    import java.io.IOException; 
    import javax.servlet.RequestDispatcher; 
    import javax.servlet.ServletException; 
    import javax.servlet.http.HttpServletRequest; 
    import javax.servlet.http.HttpServletResponse; 
    import javax.naming.*; 
    import javax.naming.directory.*; 
    import java.util.Hashtable; 

    public class Login extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { 

    public Login() { 
    super(); 
    } 

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

    final String SUCCESS = "loin.jsp"; 
    final String FAILURE = "Failure.html"; 
    String strUrl = "login.html"; 
    String username = request.getParameter("username"); 
    String password = request.getParameter("password"); 



    Hashtable env = new Hashtable(11); 

    boolean b = false; 

    env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "com.sun.jndi.ldap.LdapCtxFactory"); 
    env.put(Context.PROVIDER_URL, "ldap://localhost:10389"); 
    env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
    env.put(Context.SECURITY_PRINCIPAL, "uid="+ username +",ou=system"); 
    env.put(Context.SECURITY_CREDENTIALS, password); 

    try { 
    // Create initial context 
    DirContext ctx = new InitialDirContext(env); 

    // Close the context when we're done 
    b = true; 
    ctx.close(); 

    } catch (NamingException e) { 
    b = false; 
    }finally{ 
    if(b){ 
    System.out.print("Success"); 
    strUrl = SUCCESS; 
    }else{ 
    System.out.print("Failure"); 
    strUrl = FAILURE; 
    } 
    } 
    RequestDispatcher rd = request.getRequestDispatcher(strUrl); 
    rd.forward(request, response); 

    } 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    processRequest(request,response); 
    } 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    processRequest(request,response); 
    } 
    } 
-1

En servidores LDAP aplicación real, la contraseña se almacena en forma de código hash y siempre que cualquier gestor de acceso tiene la contraseña del usuario, la contraseña de texto sin formato es nuevo algoritmo hash con la misma clave y comprueba que la almacenada en el LDAP. Entonces, como tal, no puede obtener la contraseña simple del servidor LDAP. Entonces, si conoce la clave secreta, solo entonces puede descifrarla.

+0

No se pueden descifrar los hash de contraseñas, y no hay una 'clave secreta'. – EJP

0

Este hilo me ayudó a resolver mi caso, gracias Brandon y mel3kings me hicieron pensar.

Cuestiones relacionadas