18 February, 2012

ADF Integration With LDAP

I received last week in my work new requirement to make signing in application single sign on(sso) through active directory.
So I have a lot of solution
1- Use ADF Security and integrate with active directory LDAP from weblogic server
     This solution is declarative but customization is hard

2- Use custom java code to integrate with LDAP directly.
     This solution is good but what if I change UI development by another tool? I will redevelop again in new   framework
3- Create database package to integrate with LDAP
     I prefer this solution as I use DB to integrate with LDAP and it is unit of later maintenance and applicable for other application.


I will illustrate the last two solution

Use Custom Java Code to Integrate with LDAP
I create class for this purpose for test as below
We need some properites of LDAP
1-host name or IP of LDAP Server and port
       protected static String MY_HOST = "ldap://10.32.209.230:389";
2-Search base in LDAP
       protected static String MY_SEARCHBASE = "DC=MCIT,DC=LOCAL";
3- User in LDAP to connect by it in LDAP
       protected static String MGR_DN = "crmtest";
4-password of user which we connect by it.
       protected static String MGR_PW = "mcit@****";

We should enter search criteria to LDAP, In our example we search about use in LDAP, so I used below filter
    protected static String MY_FILTER = "sAMAccountName=mmahmoud";
as in previous example mmahmoud is user id which  I search about it in LDAP

You can run below class and see the results.


   package view;  
   
   import java.util.Hashtable;  
   import javax.naming.*;  
   import javax.naming.directory.*;  
   public class LdapTest {  
     protected static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";  
     protected static String MY_HOST = "ldap://10.32.209.230:389";  
     protected static String MY_SEARCHBASE = "DC=MCIT,DC=LOCAL";  
     protected static String MY_FILTER = "sAMAccountName=mmahmoud";  
     protected static String MGR_DN = "crmtest";  
     protected static String MGR_PW = "mcit@****";  
     public static void main(String[] args) {  
       try {  
         Hashtable params = new Hashtable();    
         params.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);  
         params.put(Context.PROVIDER_URL, MY_HOST);  
         params.put(Context.SECURITY_AUTHENTICATION, "simple");  
         params.put(Context.SECURITY_PRINCIPAL, MGR_DN);  
         params.put(Context.SECURITY_CREDENTIALS, MGR_PW);  
   
         DirContext ctx = new InitialDirContext(params);  
   
         SearchControls constraints = new SearchControls();  
   
         constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);  
   
         NamingEnumeration results = ctx.search(MY_SEARCHBASE, MY_FILTER, constraints);  
   
         if (results != null && results.hasMore()) {  
           SearchResult sr = (SearchResult)results.next();  
           String dn = sr.getName();  
           System.out.println("Desc name is " + dn);  
           Attributes attrs = sr.getAttributes();  
           System.out.println(attrs.get("sAMAccountName"));  
         } else {  
           System.out.println("Not exist User");  
         }  
       } catch (AuthenticationException e) {  
         System.out.println("You aren't authenticated on LDAP");  
       } catch (PartialResultException e) {  
         System.out.println(MY_FILTER + " Not exists in LDAP");  
       } catch (NamingException e) {  
         e.printStackTrace();  
       }  
     }  
   }  
Create database package to integrate with LDAP
I used predefined package developed by oracle DBMS_LDAP to integrate with LDAP through DB
I created my custom package as below ldap_integration

CREATE OR REPLACE PACKAGE  ldap_integration
IS
   PROCEDURE init (p_ldap_host    VARCHAR2,
                   p_ldap_port    NUMBER,
                   p_ldap_user    VARCHAR2,
                   p_ldap_pwd     VARCHAR2,
                   p_ldap_base    VARCHAR2);

   FUNCTION search_user (p_user IN VARCHAR2, p_pwd IN VARCHAR2 DEFAULT ' ')
      RETURN VARCHAR2;
END ldap_integration;
/

CREATE OR REPLACE PACKAGE BODY  ldap_integration
IS
   -- globale variables --
   GC$ldap_host   VARCHAR2 (256) ;
   GC$ldap_port   VARCHAR2 (256) ;
   GC$ldap_user   VARCHAR2 (256) ;
   GC$ldap_pwd    VARCHAR2 (256);
   GC$ldap_base   VARCHAR2 (256);

   PROCEDURE init (p_ldap_host    VARCHAR2,
                   p_ldap_port    NUMBER,
                   p_ldap_user    VARCHAR2,
                   p_ldap_pwd     VARCHAR2,
                   p_ldap_base    VARCHAR2)
   IS
   BEGIN
      GC$ldap_host := p_ldap_host;
      GC$ldap_port := p_ldap_port;
      GC$ldap_user := p_ldap_user;
      GC$ldap_pwd := p_ldap_pwd;
      GC$ldap_base := p_ldap_base;
   END init;

   FUNCTION search_user (p_user IN VARCHAR2, p_pwd IN VARCHAR2 DEFAULT ' ')
      RETURN VARCHAR2
   IS
      l_retval      PLS_INTEGER;
      l_session     DBMS_LDAP.session;
      l_attrs       DBMS_LDAP.string_collection;
      l_message     DBMS_LDAP.MESSAGE;

      l_ret_value   VARCHAR2 (500);
   BEGIN
      DBMS_LDAP.USE_EXCEPTION := TRUE;
      -- Connect to the LDAP server.
      l_session :=
         DBMS_LDAP.init (hostname => GC$ldap_host, portnum => GC$ldap_port);

      l_retval :=
         DBMS_LDAP.
         simple_bind_s (ld       => l_session,
                        dn       => GC$ldap_user,
                        passwd   => GC$ldap_pwd);


      -- Get all attributes
      l_attrs (1) := '*';                           -- retrieve all attributes
      l_retval :=
         DBMS_LDAP.search_s (ld         => l_session,
                             base       => GC$ldap_base,
                             scope      => DBMS_LDAP.SCOPE_SUBTREE,
                             filter     => 'sAMAccountName=' || p_user,
                             attrs      => l_attrs,
                             attronly   => 0,
                             res        => l_message);

      IF DBMS_LDAP.count_entries (ld => l_session, msg => l_message) > 0
      THEN
         l_ret_value := 'OK';
      ELSE
         l_ret_value := 'FALSE';
      END IF;

      -- Disconnect from the LDAP server.
      l_retval := DBMS_LDAP.unbind_s (ld => l_session);

      RETURN l_ret_value;
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.
         put_line (' sql error  : ' || SQLCODE || ' sql msg : ' || SQLERRM);

         IF l_session IS NOT NULL
         THEN
            l_retval := DBMS_LDAP.unbind_s (ld => l_session);
         END IF;

         RETURN ' sql error  : ' || SQLCODE || ' sql msg : ' || SQLERRM;
   END search_user;
END ldap_integration;
/

After creating previous package you can call it as below script
you must assign that variables to procedure INTEGRATION.INIT
1-LDAP_Host
2-LDAP Port
3-LDAP user name
4-LDAP user password
5-LDAP Base( Which base we use to search about entered user)

Then pass search user id to function LDAP_INTEGRATION.search_user that will return "OK" if user exists in LDAP otherwise It will return "FALSE".

DECLARE
   P_LDAP_HOST   VARCHAR2 (512);
   P_LDAP_PORT   NUMBER;
   P_LDAP_USER   VARCHAR2 (512);
   P_LDAP_PWD    VARCHAR2 (512);
   P_LDAP_BASE   VARCHAR2 (512);
   P_userid      VARCHAR2 (200);
BEGIN
   P_LDAP_HOST := '10.32.209.230';
   P_LDAP_PORT := 389;
   P_LDAP_USER := 'crmtest';
   P_LDAP_PWD := 'mcit@****';
   P_LDAP_BASE := 'DC=MCIT,DC=LOCAL';
   P_userid := 'mmahmoud';

   MCIT_CMS.LDAP_INTEGRATION.INIT (P_LDAP_HOST,
                                   P_LDAP_PORT,
                                   P_LDAP_USER,
                                   P_LDAP_PWD,
                                   P_LDAP_BASE);
   DBMS_OUTPUT.put_line (MCIT_CMS.LDAP_INTEGRATION.search_user (P_userid));
END;

Because I haven't a lot of time, I wrote this article quickly and briefly.
If you have any query, don't hesitate to contact me.

Thanks
Mahmoud A. El-Sayed

2 comments:

  1. LDAP Definition
    The primary access protocol for Active Directory. LDAP is an industry-standard protocol, established by the Internet Engineering Task Force (IETF), that allows users to query and update information in a directory service. Active Directory supports both LDAP version 2 and LDAP version 3.

    ReplyDelete
  2. Nice post. Sometime back I have also shared my experience on using Spring Security for LDAP authentication in Active directory on Java application. let me know how do you find it.

    ReplyDelete

ADF : Scope Variables

Oracle ADF uses many variables and each variable has a scope. There are five scopes in ADF (Application, Request, Session, View and PageFl...