Friday, July 8, 2011

Enable SSL (LDAPS) on Windows 2008 Active Directory Domain

First of all as i mention in my previous post regarding to active directory with java that i will blog on the setup of enable SSL (LDAPS) for Active directory 2008. To add new domain user from java with user password only supported by LDAPS so after looking into it I realized my Domain Controller's didn't do LDAP over SSL (LDAPS).
So after some work on it here’s the solution to enable it. I found a few posts on line but they didn't seem to be written very clear. 
I found that all you really have to do is give the DC the correct type of certificate and it will automatically do LDAP over SSL. An important requirement here is that I didn’t want to force connections to use LDAP over SSL but rather just enable it to work if something wants to use it.

Environment
Microsoft Active Directory: Windows 2008
Certificate Authority: Windows 2008 Server



Enable The Domain Controller Authentication Certificate Template on the Certificate Authority
Starting with your Certificate Authority (CA) we need to make sure that the Domain Controllers (DC's) can enroll with the CA in order to obtain the correct Certificates. There is a Certificate Template for this that exists by default. To configure this Logon to the CA and open Server Manager and then expand the roles till you get the view below.

  • Expand the tree till you see the Certificate Templates folder and look for the Domain Controller Authentication the default existing template.
  • Then expand the CA server and check if its listed under its Certificate Templates folder as well. If the Domain Controller Authentication is listed in both places then it exists and is enabled. If it isn't under the CA's Folder then we need to enable the Domain Controller Authentication Certificate Template.
  •  Right click Certificate Templates under the CA, Click New, then and Click Certificate Template to Issue. Select the Domain Controller Authentication and then click OK.
This should be all that we need to configure on the Certificate Authority.

Note: If you want to change how long the certificate is valid for or other values. You can edit the template before we enroll the Domain Controllers.

Obtain the "Domain Controller Authentication" Certificate on the Domain Controller
We need to enroll our Domain Controllers with the CA to obtain the new Domain Controller Authentication certificate. This will have to be configured on all of the Domain Controllers. But to start should tested on just one of them before continuing to configure it on all of them

  • Login into the Domain Controller you want to test the LDAP over SSL.
  • Open a command prompt as an administrator. To open a command prompt as an administrator, click Start. In Start Search, type Command Prompt. At the top of the Start menu, right-click Command Prompt, and then click Run as administrator. If the User Account Control dialog box appears, confirm that the action it displays is what you want, and then click Continue.
  • To open Microsoft Management Console (MMC), type mmc, and then press ENTER.
  • Click File, click Add/Remove Snap-in, select Certificates from the available snap-ins, and then click Add.
  • In the Certificates snap-in, click Computer Account, and then click Next.
  • In the Select Computer, click Local Computer, and then click Finish and then OK.
  • In the console tree, expand Certificates - Local Computer, expand Personal, and then expand Certificates.
    • Note: Trying to do this on a remote computers Cert store didn't work as the options to enroll wasn't there.
  • Right Click and choose All Task, Click Request New Certificate. A Before You Begin window will prompt you. Click Next.
  • Select Active Directory Enrollment Policy. And Click Next.
  • Check Domain Controller and Domain Controller Authentication and click Next.
  • In the Certificate Enrollment, a status window should show the Domain controller enrolling and then Status: Succeeded. Click Finish.


You can test that LDAPS is now working by trying to connect with LDAP with SSL. To confirm that LDAP over SSL is configured successfully follow the guide:
if you have access on server there is a tool install with active directory name ldp.exe
so just start it with start-->run

Now new window open you need to make a connection by given host and port

when connect you should find the similar message on screen

If faild to bind over given host and port you should receive the following error:
ld = ldap_sslinit("localhostd", 636, 1);
Error 81 = ldap_set_option(hLdap, LDAP_OPT_PROTOCOL_VERSION, 3);
Error 81 = ldap_connect(hLdap, NULL);
Server error: <empty>
Error <0x51>: Fail to connect to localhostd.

Now enjoy the post and configure the SSL for Active Directory 2008.

Install certificate in java keystore

Some time there is a need to communicate with server using the certificates from java client.like to secure the communication b/w client and server we must install certificate in client side such as when try to submit transaction to Paypal from API we first need certificate to store in java keystore.In my case i want to install the certificate from Active Directory2008 to perform LDAP operations like add change password,delete entry or search user using LDAP.To install certificate in keystore java provide a tool which is available in the toolkit name KeyTool.Default keystore location depend on your installed JRE like C:\Program Files\JAVA\jdk1.6.0_18\jre\lib\security\cacerts or any other.

There is lot of commands using that keytool to install certificate, it required some time to understand each command and its usage. i choose very easy approach for that. below is my java program which take parameter from user like Active directory Host Name and Port and install the certificate in default keystore.

import java.io.*;
import java.net.URL;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
public class InstallCert {

 private static final int DEFAUL_LDAP_SSL_PORT = 636; // default SSL port of active directory
   public static void main(String[] args) throws Exception {

       String host="192.168.100.175"; // IP of My Active Directory server
       int port=9999;
       char[] passphrase="changeit".
toCharArray();
//        if (args.length == 1 || args.length == 2) {
//            String[] c = args[0].split(":");
//            host = c[0];
//            port = c.length == 1 ? DEFAUL_LDAP_SSL_PORT :
Integer.parseInt(c[1]);
//            String p = args.length == 1 ? "changeit" : args[1];
//            passphrase = p.toCharArray();
//        } else {
//            System.out.println("Usage: java InstallLDAPCert
<host>[:port] [passphrase]");
//            return;
//        }
System.out.println("javaHome: "+System.getProperty("java.home"));
       File dir = new File(System.getProperty("java.home") + "/" +
"lib" + "/" + "security");
//System.out.println("sd "+dir.getAbsolutePath());
       File 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(file);
       ks.store(out, passphrase);
       out.close();

       System.out.println();
       System.out.println(cert);
       System.out.println();
       System.out.println("Added certificate to keystore " +
file.getAbsoluteFile() + " 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);
       }
   }

}


just run the program and certificate will be installed in Keystore. simple and fast sloution.
Thanks