2012-09-07 16 views
17

Ich muss LDAP-Authentifizierung für eine Anwendung durchführen.LDAP-Authentifizierung mit Java

Ich habe versucht, das folgende Programm:

import java.util.Hashtable; 

import javax.naming.Context; 
import javax.naming.NamingException; 
import javax.naming.ldap.InitialLdapContext; 
import javax.naming.ldap.LdapContext; 


public class LdapContextCreation { 
    public static void main(String[] args) { 
     LdapContextCreation ldapContxCrtn = new LdapContextCreation(); 
     LdapContext ctx = ldapContxCrtn.getLdapContext(); 
    } 
    public LdapContext getLdapContext(){ 
     LdapContext ctx = null; 
     try{ 
      Hashtable env = new Hashtable(); 
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
      env.put(Context.SECURITY_AUTHENTICATION, "Simple"); 
      //it can be <domain\\userid> something that you use for windows login 
      //it can also be 
      env.put(Context.SECURITY_PRINCIPAL, "[email protected]"); 
      env.put(Context.SECURITY_CREDENTIALS, "password"); 
      //in following property we specify ldap protocol and connection url. 
      //generally the port is 389 
      env.put(Context.PROVIDER_URL, "ldap://server.domain.com"); 
      ctx = new InitialLdapContext(env, null); 
      System.out.println("Connection Successful."); 
     }catch(NamingException nex){ 
      System.out.println("LDAP Connection: FAILED"); 
      nex.printStackTrace(); 
     } 
     return ctx; 
    } 

} 

folgende Ausnahme Anfahrt:

LDAP Connection: FAILED javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials] at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3053) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2999) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2801) at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2715) at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:305) at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:187) at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:205) at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:148) at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:78) at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:235) at javax.naming.InitialContext.initializeDefaultInitCtx(InitialContext.java:318) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:348) at javax.naming.InitialContext.internalInit(InitialContext.java:286) at javax.naming.InitialContext.init(InitialContext.java:308) at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:99) at LdapContextCreation.getLdapContext(LdapContextCreation.java:27) at LdapContextCreation.main(LdapContextCreation.java:12)

paar Punkte zu beachten:

  1. Früher war ich mit tomcat 5.3.5 aber jemand sagte mir, dass nur Kater 6 sup portiert es so, dass ich tomcat 6.0.35 heruntergeladen und derzeit nur diese Version verwendet.

  2. konfiguriert server.xml und fügte den folgenden Code -

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" connectionURL="ldap://server.domain.com:389/"
userPattern="{0}" />

  1. kommentiert den folgenden Code aus server.xml -

    <!-- Commenting for LDAP <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> -->

  2. Schritte 2 und 3 von article

  3. Jemand schlug vor, dass es einige JAR-Dateien, die auf Tomcat, um kopiert werden sollen ldap Authentifizierung auszuführen, ist, dass etwas, was ich tun muss? Und welche jar Dateien?

  4. Auch verwende ich die richtigen Anmeldeinformationen sicher, dann, was verursacht dieses Problem?

  5. Gibt es eine Möglichkeit, die richtigen Attribute für LDAP herauszufinden, wenn ich falsche verwende?

+0

Es gibt bessere Bibliotheken für diese, aber hier ist eine ähnliche Frage http://stackoverflow.com/a/12165647/1286621 ich mit @jasim um die Haupt zustimmen. Sie müssen herausfinden, welches Format Ihr LDAP-Server verwendet. Hier ist ein Beispiel für meinen Active Directory Server "CN = bindUserName, CN = Benutzer, DC = meineDepartment, DC = myNetwork". Die LDAP-Leute sollten ziemlich schnell in der Lage sein, Ihnen zu sagen, was das Format ist. Es gibt auch GUI-Tools, die sich mit LDAP verbinden und die Verzeichnisse durchsuchen können. Sprich jedoch zuerst mit deinen Admins. – Mike

+0

Nur noch ein weiterer Kommentar, Sie wissen, dass es normalerweise einen "Bind" Benutzer/Passwort gibt, der berechtigt ist, Informationen im LDAP Server nachzuschlagen? Sobald Sie an den Server gebunden haben, können Sie die Benutzeranmeldeinformationen authentifizieren. – Mike

Antwort

6

Sie den gesamten Benutzer dn in SECURITY_PRINCIPAL

wie dieser

 env.put(Context.SECURITY_PRINCIPAL, "cn=username,ou=testOu,o=test"); 
+0

Nicht wahr, es hängt von der Serverimplementierung ab. –

+1

@ Michael-O Sicher ist es wahr. (1) Es ist in der JNDI-Spezifikation. (2) Die LDAP-Authentifizierung erfolgt über eine LDAP-Bind-Operation auf allen LDAP-Serverimplementierungen. (3) Es ist die Aufgabe von JNDI, Unterschiede in der Serverimplementierung zu überwinden. – EJP

+0

@EJP, ich sprach über die Verwendung der DN nur für einen Bindeprozess. –

16

folgenden Code authentifiziert von LDAP unter Verwendung von reinem Java JNDI bieten müssen. Das Prinzip ist: -

  1. Zuerst suchen Sie den Benutzer mit einem Admin oder DN-Benutzer.
  2. Das Benutzerobjekt muss erneut mit dem Benutzeranmeldungsnachweis an LDAP übergeben werden
  3. Keine Ausnahme bedeutet - Erfolgreich authentifiziert. Else-Authentifizierung fehlgeschlagen.

Code Snippet

public static boolean authenticateJndi(String username, String password) throws Exception{ 
    Properties props = new Properties(); 
    props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
    props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT"); 
    props.put(Context.SECURITY_PRINCIPAL, "uid=adminuser,ou=special users,o=xx.com");//adminuser - User with special priviledge, dn user 
    props.put(Context.SECURITY_CREDENTIALS, "adminpassword");//dn user password 


    InitialDirContext context = new InitialDirContext(props); 

    SearchControls ctrls = new SearchControls(); 
    ctrls.setReturningAttributes(new String[] { "givenName", "sn","memberOf" }); 
    ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE); 

    NamingEnumeration<javax.naming.directory.SearchResult> answers = context.search("o=xx.com", "(uid=" + username + ")", ctrls); 
    javax.naming.directory.SearchResult result = answers.nextElement(); 

    String user = result.getNameInNamespace(); 

    try { 
     props = new Properties(); 
     props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
     props.put(Context.PROVIDER_URL, "ldap://LDAPSERVER:PORT"); 
     props.put(Context.SECURITY_PRINCIPAL, user); 
     props.put(Context.SECURITY_CREDENTIALS, password); 

    context = new InitialDirContext(props); 
    } catch (Exception e) { 
     return false; 
    } 
    return true; 
} 
+0

Ich weiß, dass dieser Eintrag ein bisschen alt ist, aber ich habe wirklich diese brennende Frage: Warum brauchen wir einen Admin-Benutzer, warum können wir nicht einfach versuchen, mit den Benutzeranmeldeinformationen zu binden, die wir an erster Stelle authentifizieren wollen? –

11

Dies ist meine LDAP Java Login Testanwendung unterstützt LDAP: // und LDAPS: // selbstsignierten Prüfzertifikat. Der Code stammt von wenigen SO-Posts, vereinfachter Implementierung und entferntem altem sun.java.* Importe.

Nutzungs
ich dies gegen Service WinAD Verzeichnis in Windows7 und Linux-Rechnern ausgeführt haben. Die Anwendung druckt Benutzernamen und Mitgliedsgruppen.

$ java -cp Klassen test.LoginLDAP url = ldap: //1.2.3.4: 389 [email protected] password = MyPwd

$ java -cp Klassen test.LoginLDAP url = ldaps: //1.2.3.4: 636 [email protected] password = myPwd

Test-Anwendung unterstützt temporäres, selbst signiertes Prüfzeugnisse für ldaps: // Protokoll, das DummySSLFactory akzeptiert jeden Server cert so Mann -in der Mitte ist möglich. Bei der Installation im echten Leben sollte das Serverzertifikat in eine lokale JKS-Keystore-Datei importiert werden und keine Dummy-Factory verwendet werden.

Die Anwendung verwendet den Benutzernamen und das Kennwort des Endbenutzers für den anfänglichen Kontext und LDAP-Abfragen, funktioniert für WinAD, weiß aber nicht, ob sie für alle ldap-Serverimplementierungen verwendet werden kann. Sie könnten einen Kontext mit dem internen Benutzernamen + pwd erstellen und dann Abfragen ausführen, um zu sehen, ob der angegebene Endbenutzer gefunden wurde.

LoginLDAP.java

package test; 

import java.util.*; 
import javax.naming.*; 
import javax.naming.directory.*; 

public class LoginLDAP { 

    public static void main(String[] args) throws Exception { 
     Map<String,String> params = createParams(args); 

     String url = params.get("url"); // ldap://1.2.3.4:389 or ldaps://1.2.3.4:636 
     String principalName = params.get("username"); // [email protected] 
     String domainName = params.get("domain"); // mydomain.com or empty 

     if (domainName==null || "".equals(domainName)) { 
      int delim = principalName.indexOf('@'); 
      domainName = principalName.substring(delim+1); 
     } 

     Properties props = new Properties(); 
     props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
     props.put(Context.PROVIDER_URL, url); 
     props.put(Context.SECURITY_PRINCIPAL, principalName); 
     props.put(Context.SECURITY_CREDENTIALS, params.get("password")); // secretpwd 
     if (url.toUpperCase().startsWith("LDAPS://")) { 
      props.put(Context.SECURITY_PROTOCOL, "ssl"); 
      props.put(Context.SECURITY_AUTHENTICATION, "simple"); 
      props.put("java.naming.ldap.factory.socket", "test.DummySSLSocketFactory");   
     } 

     InitialDirContext context = new InitialDirContext(props); 
     try { 
      SearchControls ctrls = new SearchControls(); 
      ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE); 
      NamingEnumeration<SearchResult> results = context.search(toDC(domainName),"(& (userPrincipalName="+principalName+")(objectClass=user))", ctrls); 
      if(!results.hasMore()) 
       throw new AuthenticationException("Principal name not found"); 

      SearchResult result = results.next(); 
      System.out.println("distinguisedName: " + result.getNameInNamespace()); // CN=Firstname Lastname,OU=Mycity,DC=mydomain,DC=com 

      Attribute memberOf = result.getAttributes().get("memberOf"); 
      if(memberOf!=null) { 
       for(int idx=0; idx<memberOf.size(); idx++) { 
        System.out.println("memberOf: " + memberOf.get(idx).toString()); // CN=Mygroup,CN=Users,DC=mydomain,DC=com 
        //Attribute att = context.getAttributes(memberOf.get(idx).toString(), new String[]{"CN"}).get("CN"); 
        //System.out.println(att.get().toString()); // CN part of groupname 
       } 
      } 
     } finally { 
      try { context.close(); } catch(Exception ex) { } 
     }  
    } 

    /** 
    * Create "DC=sub,DC=mydomain,DC=com" string 
    * @param domainName sub.mydomain.com 
    * @return 
    */ 
    private static String toDC(String domainName) { 
     StringBuilder buf = new StringBuilder(); 
     for (String token : domainName.split("\\.")) { 
      if(token.length()==0) continue; 
      if(buf.length()>0) buf.append(","); 
      buf.append("DC=").append(token); 
     } 
     return buf.toString(); 
    } 

    private static Map<String,String> createParams(String[] args) { 
     Map<String,String> params = new HashMap<String,String>(); 
     for(String str : args) { 
      int delim = str.indexOf('='); 
      if (delim>0) params.put(str.substring(0, delim).trim(), str.substring(delim+1).trim()); 
      else if (delim==0) params.put("", str.substring(1).trim()); 
      else params.put(str, null); 
     } 
     return params; 
    } 

} 

und SSL-Helper-Klasse.

package test; 

import java.io.*; 
import java.net.*; 
import java.security.SecureRandom; 
import java.security.cert.X509Certificate;  
import javax.net.*; 
import javax.net.ssl.*; 

public class DummySSLSocketFactory extends SSLSocketFactory { 
    private SSLSocketFactory socketFactory; 
    public DummySSLSocketFactory() { 
     try { 
      SSLContext ctx = SSLContext.getInstance("TLS"); 
      ctx.init(null, new TrustManager[]{ new DummyTrustManager()}, new SecureRandom()); 
      socketFactory = ctx.getSocketFactory(); 
     } catch (Exception ex){ throw new IllegalArgumentException(ex); } 
    } 

     public static SocketFactory getDefault() { return new DummySSLSocketFactory(); } 

     @Override public String[] getDefaultCipherSuites() { return socketFactory.getDefaultCipherSuites(); } 
     @Override public String[] getSupportedCipherSuites() { return socketFactory.getSupportedCipherSuites(); } 

     @Override public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException { 
     return socketFactory.createSocket(socket, string, i, bln); 
     } 
     @Override public Socket createSocket(String string, int i) throws IOException, UnknownHostException { 
     return socketFactory.createSocket(string, i); 
     } 
     @Override public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException { 
     return socketFactory.createSocket(string, i, ia, i1); 
     } 
     @Override public Socket createSocket(InetAddress ia, int i) throws IOException { 
     return socketFactory.createSocket(ia, i); 
     } 
     @Override public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException { 
     return socketFactory.createSocket(ia, i, ia1, i1); 
     } 
} 

class DummyTrustManager implements X509TrustManager { 
    @Override public void checkClientTrusted(X509Certificate[] xcs, String str) { 
     // do nothing 
    } 
    @Override public void checkServerTrusted(X509Certificate[] xcs, String str) { 
     /*System.out.println("checkServerTrusted for authType: " + str); // RSA 
     for(int idx=0; idx<xcs.length; idx++) { 
      X509Certificate cert = xcs[idx]; 
      System.out.println("X500Principal: " + cert.getSubjectX500Principal().getName()); 
     }*/ 
    } 
    @Override public X509Certificate[] getAcceptedIssuers() { 
     return new java.security.cert.X509Certificate[0]; 
    } 
} 
0

// Geschrieben von Mirza Qasim Ali.

// diese Klasse LDAP authentifizieren Benutzername oder E-Mail an

// einfach LdapAuth.authenticateUserAndGetInfo nennen (Benutzername, Passwort);

//. Hinweis: Konfigurieren ldapURI, requiredAttributes, ADSearchPaths, accountSuffex

import java.util *;

import javax.naming. *;

import java.util.regex. *;

import javax.naming.directory. *;

import javax.naming.ldap.InitialLdapContext;

importieren Sie javax.naming.ldap.LdapContext;

public class LdapAuth {

private final static String ldapURI = "ldap://20.200.200.200:389/DC=corp,DC=local"; 

private final static String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; 

private static String[] requiredAttributes = {"cn","givenName","sn","displayName","userPrincipalName","sAMAccountName","objectSid","userAccountControl"}; 

// sehen Sie Active Directory-Benutzer OU Hirarchie

private static String [] ADSearchPaths = {

"OU=O365 Synced Accounts,OU=ALL USERS", 

    "OU=Users,OU=O365 Synced Accounts,OU=ALL USERS", 

    "OU=In-House,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS", 

    "OU=Torbram Users,OU=Users,OU=O365 Synced Accounts,OU=ALL USERS", 

    "OU=Migrated Users,OU=TES-Users" 

};

private static String accountSuffex = "@corp.local"; // this will be used if user name is just provided 


private static void authenticateUserAndGetInfo (String user, String password) throws Exception { 

    try { 


     Hashtable<String,String> env = new Hashtable <String,String>(); 

     env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); 

     env.put(Context.PROVIDER_URL, ldapURI);  

     env.put(Context.SECURITY_AUTHENTICATION, "simple"); 

     env.put(Context.SECURITY_PRINCIPAL, user); 

     env.put(Context.SECURITY_CREDENTIALS, password); 

     DirContext ctx = new InitialDirContext(env); 

     String filter = "(sAMAccountName="+user+")"; // default for search filter username 

     if(user.contains("@")) // if user name is a email then 
      { 
       //String parts[] = user.split("\\@"); 
       //use different filter for email 
       filter = "(userPrincipalName="+user+")"; 

      } 

     SearchControls ctrl = new SearchControls(); 
     ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE); 
     ctrl.setReturningAttributes(requiredAttributes); 

     NamingEnumeration userInfo = null; 


     Integer i = 0; 
     do 
     { 
      userInfo = ctx.search(ADSearchPaths[i], filter, ctrl); 

      i++; 
     }while(!userInfo.hasMore() && i < ADSearchPaths.length); 

     if (userInfo.hasMore()) { 

      SearchResult UserDetails = (SearchResult) userInfo.next(); 

Attributes userAttr = UserDetails.getAttributes();System.out.println("adEmail = "+userAttr.get("userPrincipalName").get(0).toString()); 

       System.out.println("adFirstName = "+userAttr.get("givenName").get(0).toString()); 

       System.out.println("adLastName = "+userAttr.get("sn").get(0).toString()); 

       System.out.println("name = "+userAttr.get("cn").get(0).toString()); 

       System.out.println("AdFullName = "+userAttr.get("cn").get(0).toString()); 

     } 

     userInfo.close(); 

    } 
    catch (javax.naming.AuthenticationException e) { 

    } 
} 

}