>From a57a6e4a68e358fade3e1f217a5f5228004a1c77 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Wed, 19 Sep 2012 12:37:41 -0400
Subject: [PATCH] Changes to use standard dbuser

We create a user that can be used to connect to the database using the
subsystem cert for client auth.  We identified this user, using the seeAlso
attribute and provided certmap rules to this effect.

For this user, we used to reuse the uid = user CA-hostname-port, which is already
created for inter-system communication.  But this is problematic if more than one
dbuser exists, as the directory server may bind as the incorrect user.  In any
replication topology, there must be only one dbuser using the subsystem cert.

To simplify things, we create a new user specifically for this purpose
(pkidbuser), and we remove the seeAlso attribute from the older dbusers.

A script is needed to convert existing dogtag 9 istances to use the new user,
and set the relevant acls.  This will be done in a separate commit.
---
 .../com/netscape/certsrv/logging/AuditFormat.java  |  2 +
 .../com/netscape/certsrv/usrgrp/IUGSubsystem.java  |  8 ++++
 .../cms/servlet/csadmin/ConfigurationUtils.java    | 52 +++++++++++++++++++---
 .../netscape/cms/servlet/csadmin/DonePanel.java    | 12 +----
 .../cms/servlet/csadmin/SystemConfigService.java   |  8 +---
 .../com/netscape/cmscore/logging/AuditFormat.java  |  5 +++
 .../com/netscape/cmscore/usrgrp/UGSubsystem.java   | 47 +++++++++++++++++++
 7 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/logging/AuditFormat.java b/base/common/src/com/netscape/certsrv/logging/AuditFormat.java
index 72980aa5ad04e3c92c64a2a055c40924723054fb..005043ada55174e231c9acf823fece15a6527314 100644
--- a/base/common/src/com/netscape/certsrv/logging/AuditFormat.java
+++ b/base/common/src/com/netscape/certsrv/logging/AuditFormat.java
@@ -106,6 +106,8 @@ public class AuditFormat {
             "Admin UID: {0} removed User UID: {1} from group: {2}";
     public static final String ADDCERTSUBJECTDNFORMAT =
             "Admin UID: {0} added cert subject DN for User UID: {1}. cert DN: {2}";
+    public static final String REMOVECERTSUBJECTDNFORMAT =
+            "Admin UID: {0} removed cert subject DN for User UID: {1}. cert DN: {2}";
 
     // LDAP publishing
     public static final String LDAP_PUBLISHED_FORMAT =
diff --git a/base/common/src/com/netscape/certsrv/usrgrp/IUGSubsystem.java b/base/common/src/com/netscape/certsrv/usrgrp/IUGSubsystem.java
index eb7f84ebf4c02985c864e1c6855277f4939729bb..543b33c26bdc7863b714ffc57a229c17e766f4d4 100644
--- a/base/common/src/com/netscape/certsrv/usrgrp/IUGSubsystem.java
+++ b/base/common/src/com/netscape/certsrv/usrgrp/IUGSubsystem.java
@@ -88,6 +88,14 @@ public interface IUGSubsystem extends ISubsystem, IUsrGrp {
     public void addCertSubjectDN(IUser identity) throws EUsrGrpException, LDAPException;
 
     /**
+     * Remove a certSubjectDN field from the user
+     * @param identity
+     * @throws EUsrGrpException
+     * @throws LDAPException
+     */
+    public void removeCertSubjectDN(IUser identity) throws EUsrGrpException, LDAPException;
+
+    /**
      * Removes a user certificate for a user entry
      * given a user certificate DN (actually, a combination of version,
      * serialNumber, issuerDN, and SubjectDN), and it gets removed
diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 6cd64f654348c0b80aa216c936e2149dc966590d..afeb4c1f6fb7cd922100d78dddfd8c14182aa7ef 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -144,6 +144,7 @@ import com.netscape.certsrv.ocsp.IOCSPAuthority;
 import com.netscape.certsrv.system.InstallToken;
 import com.netscape.certsrv.system.InstallTokenRequest;
 import com.netscape.certsrv.system.SystemConfigClient;
+import com.netscape.certsrv.usrgrp.EUsrGrpException;
 import com.netscape.certsrv.usrgrp.IGroup;
 import com.netscape.certsrv.usrgrp.IUGSubsystem;
 import com.netscape.certsrv.usrgrp.IUser;
@@ -170,6 +171,7 @@ public class ConfigurationUtils {
     public static String AUTH_FAILURE = "2";
     public static final BigInteger BIG_ZERO = new BigInteger("0");
     public static final Long MINUS_ONE = Long.valueOf(-1);
+    public static final String DBUSER = "pkidbuser";
 
     public static boolean loginToken(CryptoToken token, String tokPwd) throws TokenException,
             IncorrectPasswordException {
@@ -717,8 +719,6 @@ public class ConfigurationUtils {
             BadPaddingException, NotInitializedException, NicknameConflictException, UserCertConflictException,
             NoSuchItemOnTokenException, InvalidBERException, IOException {
         byte b[] = new byte[1000000];
-        IConfigStore cs = CMS.getConfigStore();
-        String instanceRoot = cs.getString("instanceRoot");
 
         FileInputStream fis = new FileInputStream(p12File);
         while (fis.available() > 0)
@@ -1204,8 +1204,7 @@ public class ConfigurationUtils {
         String instanceId = cs.getString("instanceId");
         String cstype = cs.getString("cs.type");
 
-        String dbuser = "uid=" + LDAPUtil.escapeDN(cstype + "-" + cs.getString("machineName") + "-"
-                + cs.getString("service.securePort")) + ",ou=people," + baseDN;
+        String dbuser = "uid=" + DBUSER + ",ou= people," + baseDN;
 
         String configDir = instancePath + File.separator + cstype.toLowerCase() + File.separator + "conf";
 
@@ -3389,19 +3388,28 @@ public class ConfigurationUtils {
         }
     }
 
-    public static void setupDBUser(String dbuser) throws CertificateException, LDAPException, EBaseException,
+    public static void setupDBUser() throws CertificateException, LDAPException, EBaseException,
             NotInitializedException, ObjectNotFoundException, TokenException, IOException {
         IUGSubsystem system =
                 (IUGSubsystem) (CMS.getSubsystem(IUGSubsystem.ID));
 
+        try {
+            @SuppressWarnings("unused")
+            Enumeration<IUser> dbusers = system.findUsers(DBUSER);
+            CMS.debug("DB User already exists: " + DBUSER);
+            return;
+        } catch (EUsrGrpException e) {
+            CMS.debug("Creating DB User: " + DBUSER);
+        }
+
         String b64 = getSubsystemCert();
         if (b64 == null) {
             CMS.debug("setupDBUser(): failed to fetch subsystem cert");
             return;
         }
 
-        IUser user = system.createUser(dbuser);
-        user.setFullName(dbuser);
+        IUser user = system.createUser(DBUSER);
+        user.setFullName(DBUSER);
         user.setEmail("");
         user.setPassword("");
         user.setUserType("agentType");
@@ -3414,6 +3422,36 @@ public class ConfigurationUtils {
         CMS.debug("setupDBUser(): successfully added the user");
         system.addUserCert(user);
         CMS.debug("setupDBUser(): successfully add the user certificate");
+
+        // set subject dn
+        system.addCertSubjectDN(user);
+
+        // remove old db users
+        CMS.debug("Removing seeAlso from old dbusers");
+        removeOldDBUsers(certs[0].getSubjectDN().toString());
+    }
+
+    public static void removeOldDBUsers(String subjectDN) throws EBaseException, LDAPException {
+        IUGSubsystem system = (IUGSubsystem) (CMS.getSubsystem(IUGSubsystem.ID));
+        IConfigStore cs = CMS.getConfigStore();
+        String userbasedn = "ou=people, " + cs.getString("internaldb.basedn");
+        IConfigStore dbCfg = cs.getSubStore("internaldb");
+        ILdapConnFactory dbFactory = CMS.getLdapBoundConnFactory();
+        dbFactory.init(dbCfg);
+        LDAPConnection conn = dbFactory.getConn();
+
+        String filter = "(&(seeAlso=" + LDAPUtil.escapeDN(subjectDN) + ")(!(uid=" + DBUSER + ")))";
+        String[] attrs = null;
+        LDAPSearchResults res = conn.search(userbasedn, LDAPConnection.SCOPE_SUB, filter,
+                attrs, false);
+        if (res != null) {
+            while (res.hasMoreElements()) {
+                String uid = (String) res.next().getAttribute("uid").getStringValues().nextElement();
+                IUser user = system.getUser(uid);
+                CMS.debug("removeOldDUsers: Removing seeAlso from " + uid);
+                system.removeCertSubjectDN(user);
+            }
+        }
     }
 
     public static String getSubsystemCert() throws EBaseException, NotInitializedException, ObjectNotFoundException,
diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/DonePanel.java b/base/common/src/com/netscape/cms/servlet/csadmin/DonePanel.java
index e81afdd2f9068e27dd3c89d462e6c92805b6158e..197c16ad351c15b6bc00ec39dd21499ea293143a 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/DonePanel.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/DonePanel.java
@@ -31,8 +31,6 @@ import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.ocsp.IOCSPAuthority;
 import com.netscape.certsrv.property.PropertySet;
-import com.netscape.certsrv.usrgrp.IUGSubsystem;
-import com.netscape.certsrv.usrgrp.IUser;
 import com.netscape.cms.servlet.wizard.WizardServlet;
 import com.netscape.cmsutil.util.Utils;
 
@@ -225,16 +223,8 @@ public class DonePanel extends WizardPanelBase {
             e.printStackTrace();
         }
 
-        String dbuser = null;
         try {
-            dbuser = cs.getString("cs.type") + "-" + cs.getString("machineName") + "-"
-                    + cs.getString("service.securePort");
-            if (!sdtype.equals("new")) {
-                ConfigurationUtils.setupDBUser(dbuser);
-            }
-            IUGSubsystem system = (IUGSubsystem) (CMS.getSubsystem(IUGSubsystem.ID));
-            IUser user = system.getUser(dbuser);
-            system.addCertSubjectDN(user);
+            ConfigurationUtils.setupDBUser();
         } catch (Exception e) {
             e.printStackTrace();
             CMS.debug("DonePanel - update(): Unable to create or update dbuser" + e);
diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
index 4ae9579f29479a2e01e2e14b386f14f8a0b80f7e..3bbe3ca8099f0e722271e9bf7ae21812bffb5404 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
@@ -703,13 +703,7 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
         }
 
         try {
-            String dbuser = csType + "-" + CMS.getEEHost() + "-" + cs.getString("service.securePort");
-            if (! securityDomainType.equals(ConfigurationRequest.NEW_DOMAIN)) {
-                ConfigurationUtils.setupDBUser(dbuser);
-            }
-            IUGSubsystem system = (IUGSubsystem) (CMS.getSubsystem(IUGSubsystem.ID));
-            IUser user = system.getUser(dbuser);
-            system.addCertSubjectDN(user);
+            ConfigurationUtils.setupDBUser();
         } catch (Exception e) {
             e.printStackTrace();
             throw new PKIException("Errors in creating or updating dbuser: " + e);
diff --git a/base/common/src/com/netscape/cmscore/logging/AuditFormat.java b/base/common/src/com/netscape/cmscore/logging/AuditFormat.java
index 9ba62babbd6c401f90b461fccacda275b5e69da8..42c3b0d6f2ac2ea809f78d36b2f856dc3de3c10b 100644
--- a/base/common/src/com/netscape/cmscore/logging/AuditFormat.java
+++ b/base/common/src/com/netscape/cmscore/logging/AuditFormat.java
@@ -108,4 +108,9 @@ public class AuditFormat {
             "Admin UID: {0} added User UID: {1} to group: {2}";
     public static final String REMOVEUSERGROUPFORMAT =
             "Admin UID: {0} removed User UID: {1} from group: {2}";
+    public static final String ADDCERTSUBJECTDNFORMAT =
+            "Admin UID: {0} added cert subject DN for User UID: {1}. cert DN: {2}";
+    public static final String REMOVECERTSUBJECTDNFORMAT =
+            "Admin UID: {0} removed cert subject DN for User UID: {1}. cert DN: {2}";
+
 }
diff --git a/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java b/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
index 9e3dacb17a16f0d292476b351b9e2309cb184f1b..76132734d2f6604b8770c05a3473d7b0176d2738 100644
--- a/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
+++ b/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
@@ -820,6 +820,53 @@ public final class UGSubsystem implements IUGSubsystem {
         return;
     }
 
+    public void removeCertSubjectDN(IUser identity) throws EUsrGrpException, LDAPException {
+        User user = (User) identity;
+
+        if (user == null) {
+            return;
+        }
+
+        X509Certificate cert[] = null;
+        LDAPModificationSet addCert = new LDAPModificationSet();
+
+        if ((cert = user.getX509Certificates()) != null) {
+            LDAPAttribute attrCertDNStr = new LDAPAttribute(LDAP_ATTR_CERTDN);
+            attrCertDNStr.addValue(cert[0].getSubjectDN().toString());
+            addCert.add(LDAPModification.DELETE, attrCertDNStr);
+
+            LDAPConnection ldapconn = null;
+
+            try {
+                ldapconn = getConn();
+                ldapconn.modify("uid=" + LDAPUtil.escapeDN(user.getUserID()) +
+                        "," + getUserBaseDN(), addCert);
+                // for audit log
+                SessionContext sessionContext = SessionContext.getContext();
+                String adminId = (String) sessionContext.get(SessionContext.USER_ID);
+
+                mLogger.log(ILogger.EV_AUDIT, ILogger.S_USRGRP,
+                        AuditFormat.LEVEL, AuditFormat.REMOVECERTSUBJECTDNFORMAT,
+                        new Object[] { adminId, user.getUserID(),
+                                cert[0].getSubjectDN().toString() }
+                        );
+
+            } catch (LDAPException e) {
+                if (Debug.ON) {
+                    e.printStackTrace();
+                }
+                log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_USRGRP_ADD_USER", e.toString()));
+                throw e;
+            } catch (ELdapException e) {
+                log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_USRGRP_ADD_USER", e.toString()));
+            } finally {
+                if (ldapconn != null)
+                    returnConn(ldapconn);
+            }
+        }
+        return;
+    }
+
     /**
      * Removes a user certificate for a user entry
      * given a user certificate DN (actually, a combination of version,
-- 
1.7.11.4

