7cad94e
commit c13593770108b6d683ab3d3b43b92d67ac64a1ef
7cad94e
Author: Christina Fu <cfu@redhat.com>
7cad94e
Date:   Wed Aug 5 16:21:51 2015 -0700
7cad94e
7cad94e
    Ticket 1531 Directory auth plugin requires LDAP anonymous binds
7cad94e
    -
7cad94e
    This patch adds a feature to allow a directory based authentication plugin
7cad94e
    to use bound ldap conneciton instead of anonymous.
7cad94e
    Two files need to be edited
7cad94e
    1. <instance>/conf/password.conf
7cad94e
      add a "tag" and the password of the binding user dn to the file
7cad94e
      e.g. externalLDAP=password123
7cad94e
    2. <instance>/ca/CS.cfg
7cad94e
      add the tag to cms.passwordlist:
7cad94e
      e.g. cms.passwordlist=internaldb,replicationdb,externalLDAP
7cad94e
      add the authPrefix of the auths entry for the authentication instance
7cad94e
      e.g. externalLDAP.authPrefix=auths.instance.UserDirEnrollment
7cad94e
      add relevant entries to the authentication instance
7cad94e
      e.g. auths.instance.UserDirEnrollment.ldap.ldapBoundConn=true
7cad94e
           auths.instance.UserDirEnrollment.ldap.ldapauth.authtype=BasicAuth
7cad94e
           auths.instance.UserDirEnrollment.ldap.ldapauth.bindDN=uid=rhcs,ou=serviceaccounts,dc=EXAMPLE,dc=com
7cad94e
           auths.instance.UserDirEnrollment.ldap.ldapauth.bindPWPrompt=externalLDAP
7cad94e
7cad94e
diff --git a/base/server/cms/src/com/netscape/cms/authentication/DirBasedAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/DirBasedAuthentication.java
7cad94e
index a8a9528..d723a57 100644
7cad94e
--- a/base/server/cms/src/com/netscape/cms/authentication/DirBasedAuthentication.java
7cad94e
+++ b/base/server/cms/src/com/netscape/cms/authentication/DirBasedAuthentication.java
7cad94e
@@ -84,6 +84,8 @@ public abstract class DirBasedAuthentication
7cad94e
     protected static final String PROP_DNPATTERN = "dnpattern";
7cad94e
     protected static final String PROP_LDAPSTRINGATTRS = "ldapStringAttributes";
7cad94e
     protected static final String PROP_LDAPBYTEATTRS = "ldapByteAttributes";
7cad94e
+    protected static final String PROP_LDAP_BOUND_CONN = "ldapBoundConn";
7cad94e
+    protected static final String PROP_LDAP_BOUND_TAG = "ldapauth.bindPWPrompt";
7cad94e
 
7cad94e
     // members
7cad94e
 
7cad94e
@@ -110,6 +112,7 @@ public abstract class DirBasedAuthentication
7cad94e
     /* whether to search for member=<userDN> or member=<mGroupUserIdName>=<uid> */
7cad94e
     protected boolean mSearchGroupUserByUserdn = true;
7cad94e
 
7cad94e
+    protected boolean mBoundConnEnable = false;
7cad94e
     /* factory of anonymous ldap connections */
7cad94e
     protected ILdapConnFactory mConnFactory = null;
7cad94e
 
7cad94e
@@ -130,6 +133,9 @@ public abstract class DirBasedAuthentication
7cad94e
     /* the combined list of LDAP attriubutes to retrieve*/
7cad94e
     protected String[] mLdapAttrs = null;
7cad94e
 
7cad94e
+    /* the password prompt (tag) for the userdn of a bound connection */
7cad94e
+    protected String mTag;
7cad94e
+
7cad94e
     /* default dn pattern if left blank or not set in the config */
7cad94e
     protected static String DEFAULT_DNPATTERN =
7cad94e
             "E=$attr.mail, CN=$attr.cn, O=$dn.o, C=$dn.c";
7cad94e
@@ -255,6 +261,7 @@ public abstract class DirBasedAuthentication
7cad94e
         mName = name;
7cad94e
         mImplName = implName;
7cad94e
         mConfig = config;
7cad94e
+        String method = "DirBasedAuthentication: init: ";
7cad94e
 
7cad94e
         /* initialize ldap server configuration */
7cad94e
         mLdapConfig = mConfig.getSubStore(PROP_LDAP);
7cad94e
@@ -263,22 +270,31 @@ public abstract class DirBasedAuthentication
7cad94e
             if (mBaseDN == null || mBaseDN.trim().equals(""))
7cad94e
                 throw new EPropertyNotFound(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", "basedn"));
7cad94e
             mGroupsEnable = mLdapConfig.getBoolean(PROP_GROUPS_ENABLE, false);
7cad94e
-            CMS.debug("DirBasedAuthentication: mGroupsEnable=" + (mGroupsEnable ? "true" : "false"));
7cad94e
+            CMS.debug(method + " mGroupsEnable=" + (mGroupsEnable ? "true" : "false"));
7cad94e
             mGroupsBaseDN = mLdapConfig.getString(PROP_GROUPS_BASEDN, mBaseDN);
7cad94e
-            CMS.debug("DirBasedAuthentication: mGroupsBaseDN="+ mGroupsBaseDN);
7cad94e
+            CMS.debug(method + " mGroupsBaseDN="+ mGroupsBaseDN);
7cad94e
             mGroups= mLdapConfig.getString(PROP_GROUPS, "ou=groups");
7cad94e
-            CMS.debug("DirBasedAuthentication: mGroups="+ mGroups);
7cad94e
+            CMS.debug(method + " mGroups="+ mGroups);
7cad94e
             mGroupObjectClass = mLdapConfig.getString(PROP_GROUP_OBJECT_CLASS, "groupofuniquenames");
7cad94e
-            CMS.debug("DirBasedAuthentication: mGroupObjectClass="+ mGroupObjectClass);
7cad94e
+            CMS.debug(method + " mGroupObjectClass="+ mGroupObjectClass);
7cad94e
             mUserIDName = mLdapConfig.getString(PROP_USERID_NAME, "uid");
7cad94e
-            CMS.debug("DirBasedAuthentication: mUserIDName="+ mUserIDName);
7cad94e
+            CMS.debug(method + " mUserIDName="+ mUserIDName);
7cad94e
             mSearchGroupUserByUserdn = mLdapConfig.getBoolean(PROP_SEARCH_GROUP_USER_BY_USERDN, true);
7cad94e
-            CMS.debug("DirBasedAuthentication: mSearchGroupUserByUserdn="+ mSearchGroupUserByUserdn);
7cad94e
+            CMS.debug(method + " mSearchGroupUserByUserdn="+ mSearchGroupUserByUserdn);
7cad94e
             mGroupUserIDName = mLdapConfig.getString(PROP_GROUP_USERID_NAME, "cn");
7cad94e
-            CMS.debug("DirBasedAuthentication: mGroupUserIDName="+ mGroupUserIDName);
7cad94e
+            CMS.debug(method + " mGroupUserIDName="+ mGroupUserIDName);
7cad94e
+        }
7cad94e
+        mBoundConnEnable = mLdapConfig.getBoolean(PROP_LDAP_BOUND_CONN, false);
7cad94e
+        CMS.debug(method +" mBoundConnEnable =" + (mBoundConnEnable ? "true" : "false"));
7cad94e
+        if (mBoundConnEnable) {
7cad94e
+            mTag = mLdapConfig.getString(PROP_LDAP_BOUND_TAG);
7cad94e
+            CMS.debug(method + " getting ldap bound conn factory using id= " + mTag);
7cad94e
+            mConnFactory = CMS.getLdapBoundConnFactory(mTag);
7cad94e
+        } else {
7cad94e
+            mConnFactory = CMS.getLdapAnonConnFactory("DirBasedAuthentication");
7cad94e
         }
7cad94e
-        mConnFactory = CMS.getLdapAnonConnFactory("DirBasedAuthentication");
7cad94e
-        mConnFactory.init(mLdapConfig);
7cad94e
+        if (mConnFactory != null) // else can try again later when needed
7cad94e
+            mConnFactory.init(mLdapConfig);
7cad94e
 
7cad94e
         /* initialize dn pattern */
7cad94e
         String pattern = mConfig.getString(PROP_DNPATTERN, null);
7cad94e
@@ -372,16 +388,34 @@ public abstract class DirBasedAuthentication
7cad94e
         String userdn = null;
7cad94e
         LDAPConnection conn = null;
7cad94e
         AuthToken authToken = new AuthToken(this);
7cad94e
+        String method = "DirBasedAuthentication: authenticate:";
7cad94e
 
7cad94e
+        CMS.debug(method + " begins...mBoundConnEnable=" + mBoundConnEnable);
7cad94e
         try {
7cad94e
             if (mConnFactory == null) {
7cad94e
-                conn = null;
7cad94e
+                CMS.debug(method + " mConnFactory null, getting conn factory");
7cad94e
+                if (mBoundConnEnable) {
7cad94e
+                    mTag = mLdapConfig.getString(PROP_LDAP_BOUND_TAG);
7cad94e
+                    CMS.debug(method + " getting ldap bound conn factory using id= " + mTag);
7cad94e
+                    mConnFactory = CMS.getLdapBoundConnFactory(mTag);
7cad94e
+                } else {
7cad94e
+                    mConnFactory = CMS.getLdapAnonConnFactory("DirBasedAuthentication");
7cad94e
+                }
7cad94e
+                if (mConnFactory != null) {
7cad94e
+                    mConnFactory.init(mLdapConfig);
7cad94e
+                    CMS.debug(method + " mConnFactory gotten, calling getConn");
7cad94e
+                    conn = mConnFactory.getConn();
7cad94e
+                }
7cad94e
             } else {
7cad94e
+                CMS.debug(method + " mConnFactory class name = " + mConnFactory.getClass().getName());
7cad94e
+                CMS.debug(method + " mConnFactory not null, calling getConn");
7cad94e
                 conn = mConnFactory.getConn();
7cad94e
             }
7cad94e
 
7cad94e
             // authenticate the user and get a user entry.
7cad94e
+            CMS.debug(method + " before authenticate() call");
7cad94e
             userdn = authenticate(conn, authCred, authToken);
7cad94e
+            CMS.debug(method + " after authenticate() call");
7cad94e
             authToken.set(USER_DN, userdn);
7cad94e
 
7cad94e
             // formulate the cert info.
7cad94e
diff --git a/base/server/cms/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java
7cad94e
index 2f9fc43..e731352 100644
7cad94e
--- a/base/server/cms/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java
7cad94e
+++ b/base/server/cms/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java
7cad94e
@@ -134,10 +134,22 @@ public class UdnPwdDirAuthentication extends DirBasedAuthentication {
7cad94e
 
7cad94e
             return userdn;
7cad94e
         } catch (ELdapException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             log(ILogger.LL_FAILURE,
7cad94e
                     "Couldn't get ldap connection. Error: " + e.toString());
7cad94e
             throw e;
7cad94e
         } catch (LDAPException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             switch (e.getLDAPResultCode()) {
7cad94e
             case LDAPException.NO_SUCH_OBJECT:
7cad94e
             case LDAPException.LDAP_PARTIAL_RESULTS:
7cad94e
diff --git a/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
7cad94e
index 21e024f..26bfaab 100644
7cad94e
--- a/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
7cad94e
+++ b/base/server/cms/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
7cad94e
@@ -235,10 +235,22 @@ public class UidPwdDirAuthentication extends DirBasedAuthentication
7cad94e
             return userdn;
7cad94e
         } catch (ELdapException e) {
7cad94e
             CMS.debug("Authenticating: User authentication failure: "+e);
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
7cad94e
             throw e;
7cad94e
         } catch (LDAPException e) {
7cad94e
             CMS.debug("Authenticating: User authentication failure: "+e);
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             switch (e.getLDAPResultCode()) {
7cad94e
             case LDAPException.NO_SUCH_OBJECT:
7cad94e
             case LDAPException.LDAP_PARTIAL_RESULTS:
7cad94e
diff --git a/base/server/cms/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java
7cad94e
index ed20740..82331da 100644
7cad94e
--- a/base/server/cms/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java
7cad94e
+++ b/base/server/cms/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java
7cad94e
@@ -247,9 +247,21 @@ public class UidPwdPinDirAuthentication extends DirBasedAuthentication
7cad94e
 
7cad94e
             return userdn;
7cad94e
         } catch (ELdapException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
7cad94e
             throw e;
7cad94e
         } catch (LDAPException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             switch (e.getLDAPResultCode()) {
7cad94e
             case LDAPException.NO_SUCH_OBJECT:
7cad94e
             case LDAPException.LDAP_PARTIAL_RESULTS:
7cad94e
diff --git a/base/server/cms/src/com/netscape/cms/authentication/UserPwdDirAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/UserPwdDirAuthentication.java
7cad94e
index 7bcab25..a95dd86 100644
7cad94e
--- a/base/server/cms/src/com/netscape/cms/authentication/UserPwdDirAuthentication.java
7cad94e
+++ b/base/server/cms/src/com/netscape/cms/authentication/UserPwdDirAuthentication.java
7cad94e
@@ -187,9 +187,21 @@ public class UserPwdDirAuthentication extends DirBasedAuthentication
7cad94e
 
7cad94e
             return userdn;
7cad94e
         } catch (ELdapException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
7cad94e
             throw e;
7cad94e
         } catch (LDAPException e) {
7cad94e
+            CMS.debug("Authenticating: closing bad connection");
7cad94e
+            try {
7cad94e
+                conn.disconnect();
7cad94e
+            } catch (Exception f) {
7cad94e
+                CMS.debug("Authenticating: conn.disconnect() exception =" + f.toString());
7cad94e
+            }
7cad94e
             switch (e.getLDAPResultCode()) {
7cad94e
             case LDAPException.NO_SUCH_OBJECT:
7cad94e
             case LDAPException.LDAP_PARTIAL_RESULTS:
7cad94e
diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
7cad94e
index fa2c814..467836b 100644
7cad94e
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
7cad94e
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
7cad94e
@@ -331,6 +331,7 @@ public class CMSEngine implements ICMSEngine {
7cad94e
     }
7cad94e
 
7cad94e
     public void initializePasswordStore(IConfigStore config) throws EBaseException, IOException {
7cad94e
+        System.out.println("CMSEngine.initializePasswordStore() begins");
7cad94e
         // create and initialize mPasswordStore
7cad94e
         getPasswordStore();
7cad94e
 
7cad94e
@@ -345,6 +346,7 @@ public class CMSEngine implements ICMSEngine {
7cad94e
             String binddn;
7cad94e
             String authType;
7cad94e
             LdapConnInfo connInfo = null;
7cad94e
+            System.out.println("CMSEngine.initializePasswordStore(): tag=" + tag);
7cad94e
 
7cad94e
             if (tag.equals("internaldb")) {
7cad94e
                 authType = config.getString("internaldb.ldapauth.authtype", "BasicAuth");
7cad94e
@@ -382,8 +384,43 @@ public class CMSEngine implements ICMSEngine {
7cad94e
                 binddn = config.getString("ca.publish.ldappublish.ldap.ldapauth.bindDN");
7cad94e
 
7cad94e
             } else {
7cad94e
-                // ignore any others for now
7cad94e
-                continue;
7cad94e
+                /*
7cad94e
+                 * This section assumes a generic format of
7cad94e
+                 * <authPrefix>.ldap.xxx
7cad94e
+                 * where <authPrefix> is specified under the tag substore
7cad94e
+                 *
7cad94e
+                 * e.g.  if tag = "externalLDAP"
7cad94e
+                 *   cms.passwordlist=...,externalLDAP
7cad94e
+                 *   externalLDAP.authPrefix=auths.instance.UserDirEnrollment
7cad94e
+                 *
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapauth.authtype=BasicAuth
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapauth.bindDN=cn=Corporate Directory Manager
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapauth.bindPWPrompt=externalLDAP
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapconn.host=host.example.com
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapconn.port=389
7cad94e
+                 *   auths.instance.UserDirEnrollment.ldap.ldapconn.secureConn=false
7cad94e
+                 */
7cad94e
+                String authPrefix = config.getString(tag + ".authPrefix", null);
7cad94e
+                if (authPrefix ==  null) {
7cad94e
+                    System.out.println("CMSEngine.initializePasswordStore(): authPrefix not found...skipping");
7cad94e
+                    continue;
7cad94e
+                }
7cad94e
+                System.out.println("CMSEngine.initializePasswordStore(): authPrefix=" + authPrefix);
7cad94e
+                authType = config.getString(authPrefix +".ldap.ldapauth.authtype", "BasicAuth");
7cad94e
+                System.out.println("CMSEngine.initializePasswordStore(): authType " + authType);
7cad94e
+                if (!authType.equals("BasicAuth"))
7cad94e
+                    continue;
7cad94e
+
7cad94e
+                connInfo = new LdapConnInfo(
7cad94e
+                        config.getString(authPrefix + ".ldap.ldapconn.host"),
7cad94e
+                        config.getInteger(authPrefix + ".ldap.ldapconn.port"),
7cad94e
+                        config.getBoolean(authPrefix + ".ldap.ldapconn.secureConn"));
7cad94e
+
7cad94e
+                binddn = config.getString(authPrefix + ".ldap.ldapauth.bindDN", null);
7cad94e
+                if (binddn == null) {
7cad94e
+                    System.out.println("CMSEngine.initializePasswordStore(): binddn not found...skipping");
7cad94e
+                    continue;
7cad94e
+                }
7cad94e
             }
7cad94e
 
7cad94e
             do {