使用SSL来连接LDAP server有多种方法(http://yagodnoe.ifmo.ru/~ad/Documentation/jndi-1_4_2-tutorial/ldap/security/ssl.html#SERVER),但大都需要client端指定keystore和password,其实对于大部分应用,client会接受server端的证书,所以更通用的方法是应用前面链接中提到的Custom Socket Factory.下面给出示例:
--------------------------DummyTrustManager------------------------------
package com.auth.ldaps;
import java.security.cert.*;
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
public class DummyTrustManager implements X509TrustManager {
public void checkClientTrusted( X509Certificate[] cert, String authType) {
return;
}
public void checkServerTrusted( X509Certificate[] cert, String authType) {
return;
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
---------------------------DummySSLSocketFactory---------------------------
package com.auth.ldaps;
import java.security.cert.X509Certificate;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.ssl.*;
import javax.net.SocketFactory;
public class DummySSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory factory;
public DummySSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init( null, // No KeyManager required
new TrustManager[] { new DummyTrustManager()},
new java.security.SecureRandom());
factory = ( SSLSocketFactory) sslcontext.getSocketFactory();
} catch( Exception ex) { ex.printStackTrace(); }
}
public static SocketFactory getDefault() {
return new DummySSLSocketFactory();
}
public Socket createSocket( Socket socket, String s, int i, boolean flag) throws IOException {
return factory.createSocket( socket, s, i, flag);
}
public Socket createSocket( InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException {
return factory.createSocket( inaddr, i, inaddr1, j);
}
public Socket createSocket( InetAddress inaddr, int i) throws IOException {
return factory.createSocket( inaddr, i);
}
public Socket createSocket( String s, int i, InetAddress inaddr, int j) throws IOException {
return factory.createSocket( s, i, inaddr, j);
}
public Socket createSocket( String s, int i) throws IOException {
return factory.createSocket( s, i);
}
public String[] getDefaultCipherSuites() {
return factory.getSupportedCipherSuites();
}
public String[] getSupportedCipherSuites() {
return factory.getSupportedCipherSuites();
}
}
--------------------------LdapsAuthn test-------------------
package com.auth.ldaps;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
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 com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class LdapsAuthn {
public static void main(String args[]) {
String server = "hpt087-win32";
String port = "11636";
String admin = "uid=admin,ou=system";
String adminPass = "secret";
String testUser = "abc";
String baseDN = "ou=users,ou=system";
if (connect(server, port, admin, adminPass, testUser, baseDN)) {
System.out.println("Successful");
} else {
System.out.println("Fail");
}
}
public static boolean connect(String server, String port, String user, String passwd, String testUser, String baseDN) {
boolean result = false;
Properties env = new Properties();
String ldapURL = "ldap://" + server + ":" + port;
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, passwd);
env.put(Context.PROVIDER_URL, ldapURL);
env.put(Context.REFERRAL,"ignore");
env.put(Context.SECURITY_PROTOCOL,"ssl");
env.put("java.naming.ldap.factory.socket", "com.auth.ldaps.DummySSLSocketFactory");
try {
DirContext ctx = new InitialDirContext(env);
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration> results = ctx.search(baseDN, "uid=" + testUser, searchCtls);
while (results.hasMoreElements()) {
SearchResult sr = (SearchResult) results.next();
Attributes attributes = sr.getAttributes();
System.out.println(attributes);
}
ctx.close();
result = true;
} catch (NamingException e) {
e.printStackTrace();
}
return result;
}
}
参考资料:
http://java.itags.org/java-core-apis/49920/
http://yagodnoe.ifmo.ru/~ad/Documentation/jndi-1_4_2-tutorial/ldap/security/ssl.html#SERVER
http://blogs.sun.com/andreas/entry/no_more_unable_to_find