Thursday, March 27, 2014

Java/BPEL Authenticate & Search Active Directory

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]

Tuesday, March 25, 2014

Weblogic decrypt password

Weblogic Server uses AES encryption to save the passwords in file.The database passwords in the jdbc files or passwords in config.xml files are encrypted using a AES cipher and the AES secret key is stored in SerializedSystemIni.dat. At times we will need to decrypt this password to get the plain password.Below are the steps to decrypt the password.

1.Copy the SerializedSystemIni.dat from $DOMAIN_HOME/security folder to the $WL_HOME/common/bin folder.

The SerializedSystemIni.dat file varies across weblogic domains.

2.Create a simple python script file for example(DecryptWLPwd.py) and copy the below contents and save the file.
from weblogic.security.internal import *
from weblogic.security.internal.encryption import *
# Remind user about how to use
raw_input("Please ensure SerializedSystemIni.dat is in the current directory now, and press ENTER to continue.")
# Get encryption service
encryptionService = SerializedSystemIni.getEncryptionService(".")  
clearOrEncryptService = ClearOrEncryptedService(encryptionService)
# Get user to enter password
pwd = raw_input("Enter encrypted password (Eg. {3DES}Y1fA34S...): ")
# Remove unnecessary escape characters
preppwd = pwd.replace("\\", "")
# Decrypt the password
print "Decrypted password is: " + clearOrEncryptService.decrypt(preppwd)



3.Start the Weblogic Scripting tool from $WL_HOME/common/bin
./wlst.sh

4.Execute the script with the below command.

wls:/offline> execfile('DecryptWLPwd.py')

The script will  prompt to confirm the SerializedSystemIni.dat file in the current directory and get the encrypted password and output the decrypted password.

Thursday, March 13, 2014

ODI 11g Additional Drivers to the Standalone Agent and ODI Studio

ODI 11g connect to Firebird SQL

ODI installation includes a set of Data Direct drivers for the following technologies: Oracle, Hypersonic SQL, SQL Server, Sybase ASE, and DB2 UDB. If additional drivers and open tools are needed, they must be added to the Standalone Agent and the ODI Studio.
Even though this post explains how we can connect to Firebird SQL but same steps can be used to any JDBC supported database.

Create a new physical architecture

Create a new Data Server.
Driver Class  : org.firebirdsql.jdbc.FBDriver
Sample JDBC URL: jdbc:firebirdsql://hostname:port/F:/RESPAKDB/respak.gdb


On Windows operating systems, go to the following directory (not created until after ODI Studio is launched for the first time)
%APPDATA%\odi\oracledi\userlib

This folder contains the additional_path.txt file that allows you to declare additional files or folders outside of the /userlib directory from which the ODI Studio acquires its libraries and drivers.
Sample
; Additional paths file; You can add here paths to additional libraries
; Examples:
; C:\ java\libs\myjar.jar
; C:\ java\libs\myzip.zip
; C:\java\libs\*.jar will add all jars contained in the C:\java\libs\ directory
; C:\java\libs\**\*.jar will add all jars contained in the C:\java\libs\ directory and subdirectories
C:\Users\xxxxxxx\AppData\Roaming\odi\oracledi\userlib\jaybird-full-2.1.6.jar


Now click on the Test Connection and you should be able to see the success message as below.

Now you can proceed to create the logical schema and use it in the models and reverse engineer and use in projects.