We recently needed to create a BPEL service to authenticate users in Active Directory and also to search through the AD. For this we used the native LDAP classes in Java to connect to Active directory and embed the code in spring bean and expose as web service in Oracle SOA suite.
AD Authentication
We used the following code in the Spring bean for user authentication. public boolean isAuthenticated(String user,String pwd){
DirContext ctx = null;
boolean result=false;
Hashtable env = new Hashtable();
String ldapURL = "ldap://myhost1.company.ae:389";
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,pwd);
env.put(Context.PROVIDER_URL, ldapURL);
try {
ctx = new InitialLdapContext(env, null);
result=true;
} catch (Exception e) {
System.err.println("Invalid login for user: " + user);
}finally{
try {
if(ctx!=null)
ctx.close();
} catch (NamingException e) {
System.err.println("Invalid login for user: " + e);
}
}
return result;
}
And below is the java code to search through the Active directory. Since we have multiple domain controls and the servers hosted in Solaris which is not in the domain we had used the ping functionality to see if the domain control is up before connecting to it.
package sample.com;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Hashtable;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import javax.naming.*;
public class SearchAD {
public static void main(String[] args) {
Hashtable env = new Hashtable();
String userName ="CN=admin,OU=Application Accounts,DC=company,DC=ae";
String password = "******";
String ldapURL = getReachableHost();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, userName);
env.put(Context.SECURITY_CREDENTIALS, password);
//Used if LDAPS port is used
// env.put(Context.SECURITY_PROTOCOL,"ssl");
//connect to domain controller
env.put(Context.PROVIDER_URL, ldapURL);
try {
// Create the initial directory context
DirContext ctx = new InitialLdapContext(env, null);
SearchControls searchCtls = new SearchControls();
//Array of attributes to be returned
String returnedAtts[] ={ "sn", "mail", "cn", "givenName", "title" };
searchCtls.setReturningAttributes(returnedAtts);
//Provide the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//Provide the LDAP filter for search
String searchFilter = "(&(sn=Siva*)(mail=*))";
//Provide the Base for search
String searchBase = "DC=company,DC=ae";
// Search for objects using the filter
NamingEnumeration results =ctx.search(searchBase, searchFilter, searchCtls);
//Iterate through the results
while (results.hasMoreElements()) {
SearchResult sr = (SearchResult)results.next();
System.out.println(">>>" + sr.getName());
Attributes attribs = sr.getAttributes();
if (attribs != null) {
try {
System.out.println("surname==>" +
attribs.get("sn").get());
System.out.println("firstname==>" +
attribs.get("givenName").get());
System.out.println("Email==>" +
attribs.get("mail").get());
System.out.println(" cn==>" +
attribs.get("cn").get());
System.out.println(" Title==>" +
attribs.get("title").get());
} catch (NullPointerException e) {
System.out.println("Errors listing attributes: " + e);
e.printStackTrace();
}
}
}
ctx.close();
} catch (NamingException e) {
System.err.println("Problem searching directory: " + e);
e.printStackTrace();
}
}
public boolean isAuthenticated(String user,String pwd){
DirContext ctx = null;
boolean result=false;
Hashtable env = new Hashtable();
String ldapURL = getReachableHost();
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,pwd);
env.put(Context.PROVIDER_URL, ldapURL);
try {
ctx = new InitialLdapContext(env, null);
result=true;
} catch (Exception e) {
System.err.println("Invalid login for user: " + user);
}finally{
try {
if(ctx!=null)
ctx.close();
} catch (NamingException e) {
System.err.println("Invalid login for user: " + e);
}
}
return result;
}
//Ping the server to see if alive
public static String getReachableHost() {
String ldapURL = null;
try {
InetAddress address = InetAddress.getByName("myhost1.company.ae");
if (address.isReachable(3000)) {
ldapURL = "ldap://myhost1.company.ae:389";
} else {
address = InetAddress.getByName("myhost2.company.ae");
if (address.isReachable(3000)) {
ldapURL = "ldap://myhost2.company.ae:389";
} else {
address = InetAddress.getByName("myhost3.company.ae");
if (address.isReachable(3000)) {
ldapURL = "ldap://myhost3.company.ae:389";
} else {
address = InetAddress.getByName("myhost4.company.ae");
if (address.isReachable(3000)) {
ldapURL = "ldap://myhost4.company.ae:389";
}
}
}
}
} catch (UnknownHostException e) {
System.err.println("Unable to lookup host");
} catch (IOException e) {
System.err.println("Unable to reach host");
}
return ldapURL;
}
}
Below are some of the common exceptions thrown by the API.
Invalid AD username or password
[LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1
SSL Port instead of HTTP
javax.naming.CommunicationException: simple bind failed: myhost1.company.ae:389 [Root exception is javax.net.ssl.SSLException: java.net.SocketException: Software caused connection abort: recv failed]
javax.naming.CommunicationException: simple bind failed: myhost1.company.ae:389 [Root exception is javax.net.ssl.SSLException: java.net.SocketException: Software caused connection abort: recv failed]