>From a20beaa83d90bc18cc7e6a549433baf68b41518f Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Fri, 26 Oct 2012 12:36:14 -0400
Subject: [PATCH] Set paths for default instance

With this patch, it will be possible to install a default instance
simply by adding the passwords in the pkideployment.cfg.  This file
can then be used without additional alteration to add subsystems to the
same instance, by re-running pkispawn against the config file.

The patch makes sure that cert nicknames, database and baseDN , admin users
and client db are unique per subsystem.  An option is added to reuse the
existing server cert generated by the first subsystem and copy the
required data to all subsystems.

Ticket 379, 385
---
 .../certsrv/system/ConfigurationRequest.java       | 15 ++++-
 .../cms/servlet/csadmin/SystemConfigService.java   | 19 ++++++
 base/deploy/config/pkideployment.cfg               |  6 +-
 base/deploy/src/scriptlets/pkijython.py            | 69 +++++++++++++++++++++-
 base/deploy/src/scriptlets/pkiparser.py            | 62 ++++++++++++-------
 base/deploy/src/scriptlets/security_databases.py   | 49 +++++++--------
 6 files changed, 171 insertions(+), 49 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
index 6d71b5de177d314ed0e7d462526697f47d46d860..444aa9a4c4e21d89bce29793d4dc7ed27d02d373 100644
--- a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+++ b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
@@ -71,6 +71,7 @@ public class ConfigurationRequest {
     private static final String ADMIN_NAME = "adminName";
     private static final String ADMIN_PROFILE_ID = "adminProfileID";
     private static final String STEP_TWO = "stepTwo";
+    private static final String GENERATE_SERVER_CERT = "generateServerCert";
 
     //defaults
     public static final String TOKEN_DEFAULT = "Internal Key Storage Token";
@@ -197,6 +198,9 @@ public class ConfigurationRequest {
     @XmlElement
     protected String stepTwo;
 
+    @XmlElement(defaultValue = "true")
+    protected String generateServerCert;
+
     public ConfigurationRequest() {
         // required for JAXB
     }
@@ -241,6 +245,7 @@ public class ConfigurationRequest {
         adminName = form.getFirst(ADMIN_NAME);
         adminProfileID = form.getFirst(ADMIN_PROFILE_ID);
         stepTwo = form.getFirst(STEP_TWO);
+        generateServerCert = form.getFirst(GENERATE_SERVER_CERT);
     }
 
 
@@ -734,6 +739,14 @@ public class ConfigurationRequest {
         this.replicateSchema = replicateSchema;
     }
 
+    public String getGenerateServerCert() {
+        return generateServerCert;
+    }
+
+    public void setGenerateServerCert(String generateServerCert) {
+        this.generateServerCert = generateServerCert;
+    }
+
     @Override
     public String toString() {
         return "ConfigurationRequest [pin=XXXX" +
@@ -774,7 +787,7 @@ public class ConfigurationRequest {
                ", adminSubjectDN=" + adminSubjectDN +
                ", adminName=" + adminName +
                ", adminProfileID=" + adminProfileID +
+               ", generateServerCert=" + generateServerCert +
                ", stepTwo=" + stepTwo + "]";
     }
-
 }
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 6f126f8ce77e935d9bf2d8b50ab68ad97493c083..31fcaac9d0f176d395b63560a33b05e9c0f83ca1 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
@@ -437,6 +437,7 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
             throw new PKIException("Error in obtaining certificate chain from issuing CA: " + e);
         }
 
+        boolean generateServerCert = data.getGenerateServerCert().equalsIgnoreCase("false")? false : true;
         boolean hasSigningCert = false;
         Vector<Cert> certs = new Vector<Cert>();
         try {
@@ -454,6 +455,21 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                     if (cdata.getTag().equals(ct)) break;
                 }
 
+                if (!generateServerCert && ct.equals("sslserver")) {
+                    if (!cdata.getToken().equals("internal")) {
+                        cs.putString(csType.toLowerCase() + ".cert.sslserver.nickname", cdata.getNickname());
+                    } else {
+                        cs.putString(csType.toLowerCase() + ".cert.sslserver.nickname", data.getToken() +
+                                ":" + cdata.getNickname());
+                    }
+                    cs.putString(csType.toLowerCase() + ".sslserver.nickname", cdata.getNickname());
+                    cs.putString(csType.toLowerCase() + ".sslserver.cert", cdata.getCert());
+                    cs.putString(csType.toLowerCase() + ".sslserver.certreq", cdata.getRequest());
+                    cs.putString(csType.toLowerCase() + ".sslserver.tokenname", cdata.getToken());
+                    cs.putString(csType.toLowerCase() + ".sslserver.cert", cdata.getCert());
+                    continue;
+                }
+
                 String keytype = (cdata.getKeyType() != null) ? cdata.getKeyType() : "rsa";
 
                 String keyalgorithm = cdata.getKeyAlgorithm();
@@ -909,5 +925,8 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
             }
         }
 
+        if (data.getGenerateServerCert() == null) {
+            data.setGenerateServerCert("true");
+        }
     }
 }
diff --git a/base/deploy/config/pkideployment.cfg b/base/deploy/config/pkideployment.cfg
index 54840c8f39932cde65a7cb0b24f3f031fa6692eb..6630907a7a662295af4938c7c3ec6d7a41165b62 100644
--- a/base/deploy/config/pkideployment.cfg
+++ b/base/deploy/config/pkideployment.cfg
@@ -32,10 +32,10 @@ pki_admin_domain_name=
 pki_admin_dualkey=False
 pki_admin_email=
 pki_admin_keysize=2048
-pki_admin_name=admin
+pki_admin_name=
 pki_admin_nickname=
 pki_admin_subject_dn=
-pki_admin_uid=admin
+pki_admin_uid=
 pki_audit_group=pkiaudit
 pki_audit_signing_key_algorithm=SHA256withRSA
 pki_audit_signing_key_size=2048
@@ -62,7 +62,7 @@ pki_restart_configured_instance=True
 pki_security_domain_hostname=
 pki_security_domain_https_port=8443
 pki_security_domain_name=
-pki_security_domain_user=admin
+pki_security_domain_user=
 pki_skip_configuration=False
 pki_skip_installation=False
 pki_ssl_server_key_algorithm=SHA256withRSA
diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py
index e984e03779d5cfc069f26e043f42526cf5189880..6f71cb88bf244800532306f17b5bd18b3adfabcc 100644
--- a/base/deploy/src/scriptlets/pkijython.py
+++ b/base/deploy/src/scriptlets/pkijython.py
@@ -193,6 +193,28 @@ def generateCRMFRequest(token, keysize, subjectdn, dualkey):
         Req1 = Utils.base64encode(encoded)
         return Req1
 
+COMMENT_CHAR = '#'
+OPTION_CHAR =  '='
+def read_simple_configuration_file(filename):
+    values = {}
+    f = open(filename)
+    for line in f:
+        # First, remove comments:
+        if COMMENT_CHAR in line:
+            # split on comment char, keep only the part before
+            line, comment = line.split(COMMENT_CHAR, 1)
+        # Second, find lines with an name=value:
+        if OPTION_CHAR in line:
+            # split on name char:
+            name, value = line.split(OPTION_CHAR, 1)
+            # strip spaces:
+            name = name.strip()
+            value = value.strip()
+            # store in dictionary:
+            values[name] = value
+    f.close()
+    return values
+
 
 # PKI Deployment 'security databases' Class
 class security_databases:
@@ -361,6 +383,36 @@ class rest_client:
         cert.setToken(self.master["pki_%s_token" % tag])
         return cert
 
+    def retrieve_existing_server_cert(self, cfg_file):
+        cs_cfg = read_simple_configuration_file(cfg_file)
+        cstype = cs_cfg.get('cs.type').lower()
+        cert = SystemCertData()
+        cert.setTag(self.master["pki_ssl_server_tag"])
+        cert.setKeyAlgorithm(self.master["pki_ssl_server_key_algorithm"])
+        cert.setKeySize(self.master["pki_ssl_server_key_size"])
+        cert.setKeyType(self.master["pki_ssl_server_key_type"])
+        cert.setNickname(cs_cfg.get(cstype + ".sslserver.nickname"))
+        cert.setCert(cs_cfg.get(cstype + ".sslserver.cert"))
+        cert.setRequest(cs_cfg.get(cstype + ".sslserver.certreq"))
+        cert.setSubjectDN(self.master["pki_ssl_server_subject_dn"])
+        cert.setToken(cs_cfg.get(cstype + ".sslserver.tokenname"))
+        return cert
+
+    def tomcat_instance_subsystems(self):
+        # Return list of PKI subsystems in the specified tomcat instance
+        rv = []
+        try:
+            for subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+                path = self.master['pki_instance_path'] + "/" + subsystem.lower()
+                if os.path.exists(path) and os.path.isdir(path):
+                    rv.append(subsystem)
+        except Exception, e:
+            javasystem.out.println(
+                log.PKI_JYTHON_JAVA_CONFIGURATION_EXCEPTION + " " + str(e))
+            javasystem.exit(1)
+        return rv
+
+
     def construct_pki_configuration_data(self, token):
         data = None
         master = self.master
@@ -455,7 +507,21 @@ class rest_client:
 
             # Create 'SSL Server Certificate'
             # all subsystems
-            cert3 = self.create_system_cert("ssl_server")
+
+            # create new sslserver cert only if this is a new instance
+            cert3 = None
+            system_list = self.tomcat_instance_subsystems()
+            if len(system_list) >= 2:
+                data.setGenerateServerCert("false")
+                for subsystem in system_list:
+                    dst = master['pki_instance_path'] + '/conf/' +\
+                        subsystem.lower() + '/CS.cfg' 
+                    if subsystem != master['pki_subsystem'] and \
+                       os.path.exists(dst):
+                        cert3 = self.retrieve_existing_server_cert(dst)
+                        break
+            else:
+                cert3 = self.create_system_cert("ssl_server")
             systemCerts.add(cert3)
 
             # Create 'Subsystem Certificate'
@@ -481,6 +547,7 @@ class rest_client:
                     systemCerts.add(cert7)
 
             data.setSystemCerts(systemCerts)
+
         return data
 
     def configure_pki_data(self, data):
diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py
index d8fc6d98bb04f8554d13771108d1f98dc4374c5d..ac77c9f8722bc64c8fbcd1c20e9c8b5df6aa187a 100644
--- a/base/deploy/src/scriptlets/pkiparser.py
+++ b/base/deploy/src/scriptlets/pkiparser.py
@@ -1369,7 +1369,8 @@ def compose_pki_master_dictionary():
             config.pki_master_dict['pki_client_dir'] =\
                 os.path.join(
                     "/tmp",
-                    config.pki_master_dict['pki_instance_id'] + "_" + "client")
+                    config.pki_master_dict['pki_instance_id'] + "_" +\
+                    config.pki_subsystem + "_" + "client")
         if not len(config.pki_master_dict['pki_client_database_dir']):
             config.pki_master_dict['pki_client_database_dir'] =\
                 os.path.join(
@@ -1440,17 +1441,19 @@ def compose_pki_master_dictionary():
         #         config.pki_master_dict['pki_clone_pkcs12_path']
         #         config.pki_master_dict['pki_clone_uri']
         #         config.pki_master_dict['pki_security_domain_https_port']
-        #         config.pki_master_dict['pki_security_domain_user']
         #         config.pki_master_dict['pki_token_name']
         #
         #     The following variables are established via the specified PKI
         #     deployment configuration file and potentially overridden below:
         #
+        #         config.pki_master_dict['pki_security_domain_user']
         #         config.pki_master_dict['pki_issuing_ca']
         #         config.pki_master_dict['pki_security_domain_hostname']
         #         config.pki_master_dict['pki_security_domain_name']
         #         config.pki_master_dict['pki_subsystem_name']
         #
+        if not len(config.pki_master_dict['pki_security_domain_user']):
+            config.pki_master_dict['pki_security_domain_user'] = "caadmin"
         if not len(config.pki_master_dict['pki_subsystem_name']):
             config.pki_master_dict['pki_subsystem_name'] =\
                 config.pki_subsystem + " " +\
@@ -1534,10 +1537,12 @@ def compose_pki_master_dictionary():
                 # place a master and clone on the same machine (the method
                 # most often used for testing purposes)
                 config.pki_master_dict['pki_ds_base_dn'] =\
-                    "o=" + config.pki_master_dict['pki_instance_id']
+                    "o=" + config.pki_master_dict['pki_instance_id'] +\
+                    "-" + config.pki_subsystem
         if not len(config.pki_master_dict['pki_ds_database']):
             config.pki_master_dict['pki_ds_database'] =\
-                config.pki_master_dict['pki_instance_id']
+                config.pki_master_dict['pki_instance_id'] +\
+                "-" + config.pki_subsystem
         if not len(config.pki_master_dict['pki_ds_hostname']):
             # Guess that the Directory Server resides on the local host
             config.pki_master_dict['pki_ds_hostname'] =\
@@ -1592,17 +1597,23 @@ def compose_pki_master_dictionary():
         #         config.pki_master_dict['pki_admin_cert_request_type']
         #         config.pki_master_dict['pki_admin_dualkey']
         #         config.pki_master_dict['pki_admin_keysize']
+        #
+        #     The following variables are established via the specified PKI
+        #     deployment configuration file and potentially overridden below:
+        #
         #         config.pki_master_dict['pki_admin_name']
         #         config.pki_master_dict['pki_admin_uid']
-        #
-        #     The following variables are established via the specified PKI
-        #     deployment configuration file and potentially overridden below:
-        #
         #         config.pki_master_dict['pki_admin_email']
         #         config.pki_master_dict['pki_admin_nickname']
         #         config.pki_master_dict['pki_admin_subject_dn']
         #
         config.pki_master_dict['pki_admin_profile_id'] = "caAdminCert"
+        if not len(config.pki_master_dict['pki_admin_uid']):
+            config.pki_master_dict['pki_admin_uid'] =\
+                config.pki_subsystem.lower() + "admin"
+        if not len (config.pki_master_dict['pki_admin_name']):
+            config.pki_master_dict['pki_admin_name'] =\
+                config.pki_master_dict['pki_admin_uid']
         if not len(config.pki_master_dict['pki_admin_email']):
             config.pki_master_dict['pki_admin_email'] =\
                 config.pki_master_dict['pki_admin_name'] + "@" +\
@@ -1774,7 +1785,8 @@ def compose_pki_master_dictionary():
                                ['pki_ca_signing_nickname']):
                         config.pki_master_dict['pki_ca_signing_nickname'] =\
                             "caSigningCert" + " " + "cert-" +\
-                            config.pki_master_dict['pki_instance_id']
+                            config.pki_master_dict['pki_instance_id'] + " " +\
+                            config.pki_subsystem
                     # config.pki_master_dict['pki_ca_signing_subject_dn']
                     if config.str2bool(config.pki_master_dict['pki_external']):
                         # External CA
@@ -1841,7 +1853,8 @@ def compose_pki_master_dictionary():
                                ['pki_ocsp_signing_nickname']):
                         config.pki_master_dict['pki_ocsp_signing_nickname'] =\
                             "ocspSigningCert" + " " + "cert-" +\
-                            config.pki_master_dict['pki_instance_id']
+                            config.pki_master_dict['pki_instance_id'] + " " +\
+                            config.pki_subsystem
                     if config.str2bool(config.pki_master_dict['pki_external']):
                         # External CA
                         if not len(config.pki_master_dict\
@@ -1882,7 +1895,8 @@ def compose_pki_master_dictionary():
                                ['pki_ocsp_signing_nickname']):
                         config.pki_master_dict['pki_ocsp_signing_nickname'] =\
                             "ocspSigningCert" + " " + "cert-" +\
-                            config.pki_master_dict['pki_instance_id']
+                            config.pki_master_dict['pki_instance_id'] + " " +\
+                            config.pki_subsystem
                     if not len(config.pki_master_dict\
                                ['pki_ocsp_signing_subject_dn']):
                         config.pki_master_dict['pki_ocsp_signing_subject_dn'] =\
@@ -1913,11 +1927,11 @@ def compose_pki_master_dictionary():
         #         config.pki_master_dict['pki_ssl_server_key_algorithm']
         #         config.pki_master_dict['pki_ssl_server_key_size']
         #         config.pki_master_dict['pki_ssl_server_key_type']
-        #
-        #     The following variables are established via the specified PKI
-        #     deployment configuration file and potentially overridden below:
-        #
         #         config.pki_master_dict['pki_ssl_server_nickname']
+        #
+        #     The following variables are established via the specified PKI
+        #     deployment configuration file and potentially overridden below:
+        #
         #         config.pki_master_dict['pki_ssl_server_subject_dn']
         #         config.pki_master_dict['pki_ssl_server_token']
         #
@@ -1979,7 +1993,8 @@ def compose_pki_master_dictionary():
             if not len(config.pki_master_dict['pki_subsystem_nickname']):
                 config.pki_master_dict['pki_subsystem_nickname'] =\
                     "subsystemCert" + " " + "cert-" +\
-                    config.pki_master_dict['pki_instance_id']
+                    config.pki_master_dict['pki_instance_id'] + " " +\
+                    config.pki_subsystem
             if not len(config.pki_master_dict['pki_subsystem_subject_dn']):
                 if config.pki_master_dict['pki_subsystem'] == "RA":
                     # PKI RA
@@ -2004,7 +2019,8 @@ def compose_pki_master_dictionary():
                 if not len(config.pki_master_dict['pki_subsystem_nickname']):
                     config.pki_master_dict['pki_subsystem_nickname'] =\
                         "subsystemCert" + " " + "cert-" +\
-                        config.pki_master_dict['pki_instance_id']
+                        config.pki_master_dict['pki_instance_id'] + " " +\
+                        config.pki_subsystem
                 if not len(config.pki_master_dict['pki_subsystem_subject_dn']):
                     if config.pki_master_dict['pki_subsystem'] == "CA":
                         if config.str2bool(
@@ -2085,7 +2101,8 @@ def compose_pki_master_dictionary():
                            ['pki_audit_signing_nickname']):
                     config.pki_master_dict['pki_audit_signing_nickname'] =\
                         "auditSigningCert" + " " + "cert-" +\
-                        config.pki_master_dict['pki_instance_id']
+                        config.pki_master_dict['pki_instance_id'] +" " +\
+                        config.pki_subsystem
                 if not len(config.pki_master_dict\
                            ['pki_audit_signing_subject_dn']):
                     config.pki_master_dict['pki_audit_signing_subject_dn'] =\
@@ -2104,7 +2121,8 @@ def compose_pki_master_dictionary():
                            ['pki_audit_signing_nickname']):
                     config.pki_master_dict['pki_audit_signing_nickname'] =\
                         "auditSigningCert" + " " + "cert-" +\
-                        config.pki_master_dict['pki_instance_id']
+                        config.pki_master_dict['pki_instance_id'] + " " +\
+                        config.pki_subsystem
                 if not len(config.pki_master_dict\
                            ['pki_audit_signing_subject_dn']):
                     if config.pki_master_dict['pki_subsystem'] == "CA":
@@ -2186,7 +2204,8 @@ def compose_pki_master_dictionary():
                                ['pki_transport_nickname']):
                         config.pki_master_dict['pki_transport_nickname'] =\
                             "transportCert" + " " + "cert-" +\
-                            config.pki_master_dict['pki_instance_id']
+                            config.pki_master_dict['pki_instance_id'] + " " +\
+                            config.pki_subsystem
                     if not len(config.pki_master_dict\
                                ['pki_transport_subject_dn']):
                         config.pki_master_dict['pki_transport_subject_dn']\
@@ -2229,7 +2248,8 @@ def compose_pki_master_dictionary():
                     if not len(config.pki_master_dict['pki_storage_nickname']):
                         config.pki_master_dict['pki_storage_nickname'] =\
                             "storageCert" + " " + "cert-" +\
-                            config.pki_master_dict['pki_instance_id']
+                            config.pki_master_dict['pki_instance_id'] + " " +\
+                            config.pki_subsystem
                     if not len(config.pki_master_dict\
                                ['pki_storage_subject_dn']):
                         config.pki_master_dict['pki_storage_subject_dn']\
diff --git a/base/deploy/src/scriptlets/security_databases.py b/base/deploy/src/scriptlets/security_databases.py
index e60c5f24d15eebbb8ce172020412f2df4428cab8..f8de0c78c4a3b0664604003413de11e10e4b49dc 100644
--- a/base/deploy/src/scriptlets/security_databases.py
+++ b/base/deploy/src/scriptlets/security_databases.py
@@ -63,7 +63,10 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                 config.PKI_DEPLOYMENT_DEFAULT_SECURITY_DATABASE_PERMISSIONS)
             util.file.modify(master['pki_secmod_database'], perms=\
                 config.PKI_DEPLOYMENT_DEFAULT_SECURITY_DATABASE_PERMISSIONS)
-            rv = util.certutil.verify_certificate_exists(
+
+            if util.instance.tomcat_instance_subsystems() < 2:
+                # only create a self signed cert for a new instance  
+                rv = util.certutil.verify_certificate_exists(
                      master['pki_database_path'],
                      master['pki_cert_database'],
                      master['pki_key_database'],
@@ -71,28 +74,28 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
                      master['pki_self_signed_token'],
                      master['pki_self_signed_nickname'],
                      password_file=master['pki_shared_pfile'])
-            if not rv:
-                util.file.generate_noise_file(
-                    master['pki_self_signed_noise_file'],
-                    master['pki_self_signed_noise_bytes'])
-                util.certutil.generate_self_signed_certificate(
-                    master['pki_database_path'],
-                    master['pki_cert_database'],
-                    master['pki_key_database'],
-                    master['pki_secmod_database'],
-                    master['pki_self_signed_token'],
-                    master['pki_self_signed_nickname'],
-                    master['pki_self_signed_subject'],
-                    master['pki_self_signed_serial_number'],
-                    master['pki_self_signed_validity_period'],
-                    master['pki_self_signed_issuer_name'],
-                    master['pki_self_signed_trustargs'],
-                    master['pki_self_signed_noise_file'],
-                    password_file=master['pki_shared_pfile'])
-                # Delete the temporary 'noise' file
-                util.file.delete(master['pki_self_signed_noise_file'])
-            # Delete the temporary 'pfile'
-            util.file.delete(master['pki_shared_pfile'])
+                if not rv:
+                    util.file.generate_noise_file(
+                        master['pki_self_signed_noise_file'],
+                        master['pki_self_signed_noise_bytes'])
+                    util.certutil.generate_self_signed_certificate(
+                        master['pki_database_path'],
+                        master['pki_cert_database'],
+                        master['pki_key_database'],
+                        master['pki_secmod_database'],
+                        master['pki_self_signed_token'],
+                        master['pki_self_signed_nickname'],
+                        master['pki_self_signed_subject'],
+                        master['pki_self_signed_serial_number'],
+                        master['pki_self_signed_validity_period'],
+                        master['pki_self_signed_issuer_name'],
+                        master['pki_self_signed_trustargs'],
+                        master['pki_self_signed_noise_file'],
+                        password_file=master['pki_shared_pfile'])
+                    # Delete the temporary 'noise' file
+                    util.file.delete(master['pki_self_signed_noise_file'])
+                # Delete the temporary 'pfile'
+                util.file.delete(master['pki_shared_pfile'])
         else:
             util.password.create_password_conf(
                 master['pki_shared_password_conf'],
-- 
1.7.11.7

