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

Friday, January 21, 2011

Active Diresctory Quick start part 1

Today i am writing about Microsoft Active Directory 2008 to implement the SSO(Single Sign On).
As know SSO is the hottest these days on internet and manny large companies ( Microsoft,Google etc ) already implement this  for their group of application.I think no need to intro of SSO i just start to log my idea here before it will flush from my brain.
we also implementing the SSO for our client which is basically giant school system of USA and they have dozen of applications for students and Administration.They basically want to implement such a system by which users login on application and on their domain system using only single credential so Active Directory is using to store the users information for both the applications and systems.
Now talking from the code side i explorer the java core JNDI technique to authenticate the user and also used my favorite Spring-LDAP Template.so i will show both code.
Lets start from core JAVA JNDI no more explanation just code to remembering

/**
     *
     * @param sn
     * @param password
     * @return
     */
    public boolean authenticate(String username, String password) {
        boolean flag = false;
        DirContext authContext =null;
        String base = "ou=Students,DC=lti-student,DC=test";
        String dn = "cn=" + username;
        String ldapURL = "ldap://localhost:389/" + base;

        // Setup environment for authenticating

        Hashtable<String, String> environment = new Hashtable<String, String>();
        environment.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        environment.put(Context.PROVIDER_URL, ldapURL);
        environment.put(Context.SECURITY_AUTHENTICATION, "simple");
        environment.put(Context.SECURITY_PRINCIPAL, username);//+",ou=Students,DC=lti-student,DC=test"
        environment.put(Context.SECURITY_CREDENTIALS, password);
        //environment.put(Context.SECURITY_PROTOCOL, "ssl");
       
        try {
             authContext = new InitialDirContext(environment);
            flag = true;
           
            // user is authenticated

        } catch (AuthenticationException ex) {
            // Authentication failed
            flag = false;
            ex.printStackTrace();

        } catch (NamingException ex) {
            flag = false;
            ex.printStackTrace();
        }
        finally{
            try {
                authContext.close();
                environment.clear();

            } catch (NamingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return flag;
    }


i hope you understand whats is this basically code, just taking 2 parameter userDn and password and try to bind with active directory if sucessfully bind return true if fail return false.

ok now moving the Spring-LDAP Template code which is more sophisticated and widely using



    public boolean authenticate(String userDn,String password)
    {
        String base = "ou=Students,DC=lti-student,DC=test";
        String ldapURL = "ldap://localhost:389/" + base;
        DirContext ctx = null;
        LdapContextSource contextSource = new LdapContextSource();
        contextSource.setUrl(ldapURL);                
contextSource.setUserDn("YOUR_OPTIONAL_ADMIN_USER_DN");
contextSource.setPassword("YOUR_OPTIONAL_ADMIN_PWD");
        contextSource.setBase(base);
        try {
            contextSource.afterPropertiesSet();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        try {
            ctx = contextSource.getContext(
userDn,password);
            return true;
        } catch (Exception e) {
            // Context creation failed - authentication did not succeed
            return false;
        }
    }



simply taking 2 parameter and try to bind if success return true otherwise false
so i show the both technique choice is your which one you would used but i prefer Spring-LDAP template less code and managed API.

I will write the full setup and using of Active Directory 2008 with operation of adding ,deleting,update user code in future InshaALLAH.
Ok thanks enjoy the code.


Thursday, January 6, 2011

Awesome HtmlUnit

I grabbed (scraping) more than 100 international web sites which include both the job portal and for RRS Feed data in my last company. I used the open source Html Parser for this purpose.this is very interesting library i parse many websites which include search result like Google.
Today i show most interesting API example which is used for scrapping and testing. i feel this is the ever best scrapping API because of providing full control with html from code.i am talking about HtmlUnit.
In the following example i show you how i can parse the data before providing the search criteria.
Suppose you have some web site which is show you first Html for including text Fields,html Select,check boxes etc. you need to first enter your input and when received result parse all the records.let suppose you have the following web sites.

Step1: download the htmlUnit library and add in your project.
I only show you how you can submit the html Form and receive the result of pages after setting the search criteria on first page.

Step:2 use the below code which first input the html form and submit and receive the results.



import com.gargoylesoftware.htmlunit.ProxyConfig;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
/**
 *
 * @author noman.sadiq
 *
 */
public class UniTest{
protected HtmlPage currentPage;
   
       
    public static void main(String[] args) {
        try{
            WebClient webClient = new WebClient();
            ProxyConfig pc=new ProxyConfig();
            pc.setProxyHost("192.168.100.16");
            pc.setProxyPort(8080);
            webClient.setProxyConfig(pc);
           
            HtmlPage currentPage = webClient.getPage("http://www.fsa.gov.uk/register/firmSearchForm.do");
        //    System.out.println(currentPage.asXml());
            System.out.println("current URL: "+currentPage.getUrl());

            // setting the Firm name
            HtmlInput queryInput = currentPage.getElementByName("firmName");
            queryInput.setValueAttribute("AXA");
            // select search type
            HtmlSelect select= currentPage.getElementByName("searchType");
            select.setSelectedAttribute("2", true);
           
            // set authorized true
            HtmlCheckBoxInput checkbox= currentPage.getElementByName("currAuthorisedInd");
            checkbox.setChecked(true);
           
            // submit the form
            HtmlSubmitInput submitBtn = currentPage.getElementByName("Submit");
            currentPage = submitBtn.click();
           
            System.out.println(currentPage.asXml());

//  now parse the result like using the anchor Tag or table or result what ever.
           
        }
        catch (Exception e) {
            e.printStackTrace();
        }

    }
}


when you received the result on console save it as html page,when you open you will see the result page look like that
so you successfully submit the html form after fill the search criteria now you can parse the required data. you can follow the link and also scrap the data on next level.

This is very powerful library for testing and scrapping in Java enjoy! it.

Sunday, January 2, 2011

JAVA+SSL

Today post is related to Java SSL(Secure Sokcket Layer). sometimes we need to make connection b/w client and server secure to exchange the information which may be confidential like storing user passwor in windows Active Direcrtory using java LDAP API or connection to HTTPS need SSL.
Today i show you some ticks which will be very helpfull when you using SSL,or installing certificate in your keystore or want to disable certificate.
All my blog are just for my quick review notes to remeber the shortcuts for the technology so before reading this blog i hope you realy need it,otherwise just increase your knowledge.


ok i start with sample application of client and server.both the client and server try to communicate over SSL. to ensure their communication first create the certificate for them.i use the keytool utility which is available in jdk.


Step1: Run the below command in command prompt and create the certificate in C drive.
keytool -genkey -keystore c:/mySrvKeystore -keyalg RSA
when you run this command it ask for the password and other information related to certificate creation like first lastName,OU,city state country code etc. in last keytool show you your provided infomation and when you press YES it again asked you for the password so entert he same password and finish the process of certificate creation. for this example i choose the password "changeit" without qouts.


Step2 below is the code which show the server and client class in java

EchoServer:
import javax.net.ssl.SSLServerSocket; 
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * 
 * @author noman sadiq
 *
 */
public class EchoServer {
    public static void main(String[] arstring) {
        try {
// your keystore certificate and password
         System.setProperty("javax.net.ssl.keyStore","c:/mySrvKeystore");
         System.setProperty("javax.net.ssl.keyStorePassword","changeit");
            System.out.println("started");

            SSLServerSocketFactory sslserversocketfactory =
                    (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            SSLServerSocket sslserversocket =
                    (SSLServerSocket) sslserversocketfactory.createServerSocket(9999);
            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();

            InputStream inputstream = sslsocket.getInputStream();
            InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
            BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

            String string = null;
            while ((string = bufferedreader.readLine()) != null) {
                System.out.println(string);
                System.out.flush();
            }
            
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}
      

EchoClient:

import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;

public class EchoClient {
public static void main(String[] arstring) {
try {
   SocketFactory sslsocketfactory=null;
// keystore location and password
//System.setProperty("javax.net.ssl.keyStore","c:/mySrvKeystore");
         //System.setProperty("javax.net.ssl.keyStorePassword","changeit");
           
   sslsocketfactory = BlindSSLSocketFactoryTest.getDefault();
     
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
"localhost", 9999);

InputStream inputstream = System.in;
InputStreamReader inputstreamreader = new InputStreamReader(
inputstream);
BufferedReader bufferedreader = new BufferedReader(
inputstreamreader);

OutputStream outputstream = sslsocket.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(
outputstream);
BufferedWriter bufferedwriter = new BufferedWriter(
outputstreamwriter);

String string = null;
while ((string = bufferedreader.readLine()) != null) {
bufferedwriter.write(string + '\n');
bufferedwriter.flush();
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}


now the magic class is which disable the certificate from the client side and without mentin any certificate we can easy communicate the on SSL.


BlindSSLSocketFactoryTest:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


/**
 * BlindSSLSocketFactoryTest
 *  Simple test to show an Active Directory (LDAP)
 *  and HTTPS connection without verifying the 
 *  server's certificate.
 *  
 * @author noman sadiq
 */
public class BlindSSLSocketFactoryTest extends SocketFactory {
private static SocketFactory blindFactory = null;

/**
* Builds an all trusting "blind" ssl socket factory.
*/
static {
// create a trust manager that will purposefully fall down on the
// job
TrustManager[] blindTrustMan = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] c, String a) { }
public void checkServerTrusted(X509Certificate[] c, String a) { }
} };


// create our "blind" ssl socket factory with our lazy trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, blindTrustMan, new java.security.SecureRandom());
blindFactory = sc.getSocketFactory();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}


/**
* @see javax.net.SocketFactory#getDefault()
*/
public static SocketFactory getDefault() {
return new BlindSSLSocketFactoryTest();
}




/**
* @see javax.net.SocketFactory#createSocket(java.lang.String, int)
*/
public Socket createSocket(String arg0, int arg1) throws IOException,
UnknownHostException {
return blindFactory.createSocket(arg0, arg1);
}


/**
* @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
*/
public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
return blindFactory.createSocket(arg0, arg1);
}


/**
* @see javax.net.SocketFactory#createSocket(java.lang.String, int,
*      java.net.InetAddress, int)
*/
public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3)
throws IOException, UnknownHostException {
return blindFactory.createSocket(arg0, arg1, arg2, arg3);
}


/**
* @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int,
*      java.net.InetAddress, int)
*/
public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2,
int arg3) throws IOException {
return blindFactory.createSocket(arg0, arg1, arg2, arg3);
}


}




in client class you check the instance of BlindSSLSocketFactoryTest class
 sslsocketfactory = BlindSSLSocketFactoryTest.getDefault();
you also check the commented code in client class which is for certificate keystore but it not mention just in comments
// keystore location and password
//System.setProperty("javax.net.ssl.keyStore","c:/mySrvKeystore");
         //System.setProperty("javax.net.ssl.keyStorePassword","changeit");


so magic is already done with BlindSSLSocketFactoryTest class we just need to run the first server and then client and check the commuinication without given the error.same BlindSSLSocketFactoryTest is used for the connection with Active Directory using SSL(ldaps://localhost:636)


when you run client class might be possible you find such a exception in client side


javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

ok it need to add certificate in keystore for that purpose i create a programe which connect with server and get the certificate and automaticaly insert it in keystore and generate the keystore where you run the class.
This is very intresting program and very helpfull when we want to install server certificate in cient side without having the orignal certificate.


Enjoy the SSL disable method.