->Generating LDAP Certificate to Trusted Java Keys tore for java client:

LDAP Connection Process: You can download this document check here

This document is the purpose of how to generate a keystore file by grabbing the certificate from LDAP server and placing that file in java keystore for java clients, and the information how to Authenticate LDAP server successfully using java client.

First we need to verify if the LDAP server has any certificates in order to connect.

Generating LDAP Certificate to Trusted Java Keys tore for java client:

When working on a client that works with an SSL enabled server running in https/ldaps protocol, you could get error unable to find valid certification path to requested target if the server certificate is not issued by certification authority, but a self signed or issued by a private CMS.

Here is the process how to get the certificate and string into keystore file.

  1. All you need to do is to add the server certificate to your trusted Java key store if your client is written in Java. You might be wondering how as if you cannot access the machine where the server is installed. There is a simple program (InstallCert.java) can help you.

import java.io.*;

import java.net.URL;

import java.security.*;

import java.security.cert.*;

import javax.net.ssl.*;

public class InstallCert {

public static void main(String[] args) throws Exception {

String host;

int port;

char[] passphrase;

host = “domain”;  //where you LDAP server is runngin

port = 636;

String p = “changeit”;

passphrase = p.toCharArray();

File file = new File(“jssecacerts”);

System.out.println(file.getAbsolutePath());

if (file.isFile() == false) {

char SEP = File.separatorChar;

File dir = new File(System.getProperty(“java.home”) + SEP

+ “lib” + SEP + “security”);

file = new File(dir, “jssecacerts”);

if (file.isFile() == false) {

file = new File(dir, “cacerts”);

}

}

System.out.println(“Loading KeyStore ” + file + “…”);

InputStream in = new FileInputStream(file);

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

ks.load(in, passphrase);

in.close();

SSLContext context = SSLContext.getInstance(“TLS”);

TrustManagerFactory tmf =

TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tmf.init(ks);

X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];

SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);

context.init(null, new TrustManager[] {tm}, null);

SSLSocketFactory factory = context.getSocketFactory();

System.out.println(“Opening connection to ” + host + “:” + port + “…”);

SSLSocket socket = (SSLSocket)factory.createSocket(host, port);

socket.setSoTimeout(10000);

try {

System.out.println(“Starting SSL handshake…”);

socket.startHandshake();

socket.close();

System.out.println ();

System.out.println (“No errors, certificate is already trusted”);

} catch (SSLException e) {

System.out.println ();

e.printStackTrace(System.out);

}

X509Certificate[] chain = tm.chain;

if (chain == null) {

System.out.println (“Could not obtain server certificate chain”);

return;

}

BufferedReader reader =

new BufferedReader(new InputStreamReader(System.in));

System.out.println ();

System.out.println (“Server sent ” + chain.length + ” certificate(s):”);

System.out.println();

MessageDigest sha1 = MessageDigest.getInstance(“SHA1”);

MessageDigest md5 = MessageDigest.getInstance(“MD5″);

for (int i = 0; i < chain.length; i++) {

X509Certificate cert = chain[i];

System.out.println

(” ” + (i + 1) + ” Subject ” + cert.getSubjectDN());

System.out.println(”   Issuer  ” + cert.getIssuerDN());

sha1.update(cert.getEncoded());

System.out.println(”   sha1    ” + toHexString(sha1.digest()));

md5.update(cert.getEncoded());

System.out.println(”   md5     ” + toHexString(md5.digest()));

System.out.println();

}

System.out.println(“Enter certificate to add to trusted keystore or ‘q’ to quit: [1]”);

String line = reader.readLine().trim();

int k;

try {

k = (line.length() == 0) ? 0 : Integer.parseInt(line) – 1;

} catch (NumberFormatException e) {

System.out.println(“KeyStore not changed”);

return;

}

X509Certificate cert = chain[k];

String alias = host + “-” + (k + 1);

ks.setCertificateEntry(alias, cert);

OutputStream out = new FileOutputStream(“jssecacerts”);

ks.store(out, passphrase);

out.close();

System.out.println();

System.out.println(cert);

System.out.println();

System.out.println

(“Added certificate to keystore ‘jssecacerts’ using alias ‘”

+ alias + “‘”);

}

private static final char[] HEXDIGITS = “0123456789abcdef”.toCharArray();

private static String toHexString(byte[] bytes) {

StringBuilder sb = new StringBuilder(bytes.length * 3);

for (int b : bytes) {

b &= 0xff;

sb.append(HEXDIGITS[b >> 4]);

sb.append(HEXDIGITS[b & 15]);

sb.append(‘ ‘);

}

return sb.toString();

}

private static class SavingTrustManager implements X509TrustManager {

private final X509TrustManager tm;

private X509Certificate[] chain;

SavingTrustManager(X509TrustManager tm) {

this.tm = tm;

}

public X509Certificate[] getAcceptedIssuers() {

throw new UnsupportedOperationException();

}

public void checkClientTrusted(X509Certificate[] chain, String authType)

throws CertificateException {

throw new UnsupportedOperationException();

}

public void checkServerTrusted(X509Certificate[] chain, String authType)

throws CertificateException {

this.chain = chain;

tm.checkServerTrusted(chain, authType);

}

}

}

Update that program with the appropriate Input variables like host name, port, and password. Host Name : yahoo.com

This is the host address where LDAP server directory is located.

Port: 636

Mentioned for this LDAP server directory.

Password:  changeit

A password designed to protect the keystore file from tampering. Java level keystores (cacerts and jssecacerts) usually require the password changeit; which is default for SUN LDAP server.

  1. Then execute this program as standalone application directly. This program opened a connection to the specified host and started an SSL handshake. It printed the exception stack trace of the error that occurred and shows you the certificates used by the server. Now it prompts you add the certificate to your trusted KeyStore.
  1. If you want to continue with creating the file add the certificate, then ‘1’, if you want to quit, then ‘q’, or  other numbers to add other certificates, even a CA certificate, but you usually don’t want to do that. Once you have made your choice, the program will display the complete certificate and then added it to a Java KeyStore named ‘jssecacerts’ in the current directory.

Enter 1 and press Enter key, then added certificate to keystore ‘jssecacerts’ using alias ‘domainname-1’ (A mandatory, unique alias for the certificate in the trust store)

  1. To use it in your program, either configure JSSE to use it as its trust store or copy it into your $JAVA_HOME/jre/lib/security directory. If you want all Java applications to recognize the certificate as trusted and not just JSSE, you could also overwrite the cacerts file(This is bad approach) in that directory.

After all that, JSSE will be able to complete a handshake with the host, which you can verify by running the program again.

Authenticating LDAP server with Java Client:

Here is the Test program which helps to authenticate to LDAP successfully.

import javax.naming.*;

import javax.naming.directory.*;

import java.util.Hashtable;

/**

* Demonstrates how to create an initial context to an LDAP server

* using simple authentication.

*/

class SimpleAuthenticate {

public static void main(String[] args) {

Hashtable authEnv = new Hashtable(11);

String passWord = “pass_1234”;

String dn = “uid=skk27,ou=People,dc=domain,dc=edu”;

String ldapURL = ” ldaps://host:636″;

authEnv.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”);

authEnv.put(Context.PROVIDER_URL, ldapURL);

authEnv.put(Context.SECURITY_AUTHENTICATION, “simple”);

authEnv.put(Context.SECURITY_PRINCIPAL, dn);

authEnv.put(Context.SECURITY_CREDENTIALS, passWord);

try {

DirContext authContext = new InitialDirContext(authEnv);

System.out.println(“Authentication Success!”);

} catch (AuthenticationException authEx) {

System.out.println(“Authentication failed!”);

} catch (NamingException namEx) {

System.out.println(“Something went wrong!”);

namEx.printStackTrace();

}

}

}

Explanation:

1)      authEnv.put(Context.INITIAL_CONTEXT_FACTORY, “com.sun.jndi.ldap.LdapCtxFactory”);

Constant that holds the name of the environment property for specifying the initial context factory to use. We need to use fully qualified Ldap context object.

Here we are using “com.sun.jndi.ldap.LdapCtxFactory”, The Naming context factory that wraps the SUN LDAP factory.

2)  authEnv.put(Context.PROVIDER_URL, ldapURL);

Constant that holds the URL where the LDAP server is running with port number

3)   authEnv.put(Context.SECURITY_AUTHENTICATION, “simple”);

Specifies the authentication mechanism to use. For the Sun LDAP service provider, this can be one of the following strings: "none", "simple", “SASL”. In our case we used “simple” which is already set for this LDAP server.

4)      authEnv.put(Context.SECURITY_PRINCIPAL, dn);

Constant that holds the name of the environment property for specifying the identity of the principal for authenticating the caller to the service. The format of the principal depends on the authentication scheme. If this property is unspecified, the behavior is determined by the service provider.

In order to authenticate on LDAP, we need to build the DN like in the following.

Ex: dn = “uid=skk27,ou=People,dc=domain,dc=edu”;

As per LDAP authentication we need create the DN like the above, here

uid = User ID, in the LDAP server

ou = Organizational Unit, which is assigned during the creation of account for uid in the LDAP directory.

dc = Domain Component, here domain.edu (like yahoo.com) is the domain component.

5) authEnv.put(Context.SECURITY_CREDENTIALS, passWord);

Constant that holds the name of the environment property for specifying the credentials of the principal for authenticating the caller to the service.

Password on uid’s account.

>Javac SimpleAuthenticate.java

>Java SimpleAuthenticate

If you get the Message “Authentication Success!”, then you got to Authenticate Successfully.

5 Comments

  1. Ahmed said,

    September 9, 2009 at 9:16 AM

    Hi Sumant, thanks for your interested entry.. i have used your program to establish a connection from a java client running on windows xp to a LDAP server running on Suse 10 (both on same network). i need this LDAP server to authenticate uses. The LDAP server has an self-signed certificated and i have a copy of this certificate on the client machine. So, running your application on the client (without pointing to the certificate file) breaks at the point when it trying to open connection to the LDAP sever

    System.out.println(”Opening connection to ” + host + “:” + port + “…”);
    SSLSocket socket = (SSLSocket)factory.createSocket(host, port);

    So, can i use your program with the saved certificate at the client machine to establish connection? why it breaks and can’t connect to LDAP? note: i can connect and authenticate uses without using ssl.

    Thanks for your help in advance.

    Ahmed

    • sumant said,

      September 9, 2009 at 3:56 PM

      Hi Ahmmed,

      My program is just hook to your LDAP server and get the certificate file. It won’t breaks until your LDAP server is running out of network. Once you get the certificate (You need to change the file path in this program), copy that certificate file and paste to your jre security location. Then your client can access to LDAP server.

      If you already have the certificate file (not certificate), you can copy that to jre security location.

  2. Tahir Akram said,

    October 8, 2009 at 4:03 PM

    I also have same problem I have created jssecacerts now please tell me how can I overwrite cacerts in $JAVA_HOME/jre/lib/security. Overwriting mean deleting cacerts file? Becasue I copied jssecacerts in the said dir but still getting exception.

    I will love to see help on it.

    Note: I am hitting on a https URL throught URLConnection class. It was working fine. Dont know why I am getting problem now.

    Thanks.

    • sumant said,

      February 19, 2010 at 10:00 PM

      Hey Tahir, Sorry for delaying, I think you already solved this problem. If not, let me know so that I can clear you

  3. February 18, 2013 at 11:03 AM

    After looking into a handful of the articles on your website, I really like your way of
    writing a blog. I bookmarked it to my bookmark site list and will be checking back
    in the near future. Please visit my web site too and let me know
    what you think.


Leave a reply to sumant Cancel reply