From b7b3bcfecc792ea689af2ecc554e12b42a58f1ce Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Tue, 18 Dec 2012 14:46:41 -0500
Subject: [PATCH] Added interactive subsystem installation.

The pkispawn has been modified such that the configuration file
and subsystem type are optional. The pkidestroy has been modified
such that the instance name and subsystem type are optional.
If any of these options are not specified they will enter an
interactive mode.

Ticket #380
---
 base/deploy/etc/default.cfg                        |  13 +-
 base/deploy/man/man5/pki_default.cfg.5             |   4 +-
 base/deploy/man/man8/pkispawn.8                    |   2 +-
 base/deploy/src/pkidestroy                         |  68 ++++--
 base/deploy/src/pkispawn                           | 128 ++++++++--
 .../deploy/src/scriptlets/infrastructure_layout.py |  11 +-
 base/deploy/src/scriptlets/pkiconfig.py            |   5 +-
 base/deploy/src/scriptlets/pkijython.py            |   4 +-
 base/deploy/src/scriptlets/pkiparser.py            | 263 ++++++++++++++-------
 9 files changed, 354 insertions(+), 144 deletions(-)

diff --git a/base/deploy/etc/default.cfg b/base/deploy/etc/default.cfg
index 3106ba53fa47b5e6ec0159685b3d305b1a49375f..9dfc4b29b4d175843481e34155a874b8d60874e1 100644
--- a/base/deploy/etc/default.cfg
+++ b/base/deploy/etc/default.cfg
@@ -57,12 +57,12 @@ destroy_scriplets=
 # case someone wants to override them in their config file.
 #
 # Tomcat instances:
-# pki_instance_name=pki_tomcat 
+# pki_instance_name=pki-tomcat
 # pki_https_port=8443
 # pki_http_port=8080
 #
 # Apache instances:
-# pki_instance_name=pki_tomcat
+# pki_instance_name=pki-apache
 # pki_https_port=443
 # pki_http_port=80
 
@@ -91,13 +91,16 @@ pki_ds_password=
 pki_ds_remove_data=True
 pki_ds_secure_connection=False
 pki_group=pkiuser
-pki_issuing_ca=
+pki_issuing_ca_hostname=%(pki_security_domain_hostname)s
+pki_issuing_ca_https_port=%(pki_security_domain_https_port)s
+pki_issuing_ca_uri=https://%(pki_issuing_ca_hostname)s:%(pki_issuing_ca_https_port)s
+pki_issuing_ca=%(pki_issuing_ca_uri)s
 pki_restart_configured_instance=True
 pki_security_domain_hostname=%(pki_hostname)s
 pki_security_domain_https_port=8443
 pki_security_domain_name=%(pki_dns_domainname)s Security Domain
 pki_security_domain_password=
-pki_security_domain_user=
+pki_security_domain_user=caadmin
 pki_skip_configuration=False
 pki_skip_installation=False
 pki_ssl_server_key_algorithm=SHA256withRSA
@@ -125,7 +128,7 @@ pki_client_pkcs12_password_conf=%(pki_client_subsystem_dir)s/pkcs12_password.con
 pki_client_cert_database=%(pki_client_database_dir)s/cert8.db
 pki_client_key_database=%(pki_client_database_dir)s/key3.db
 pki_client_secmod_database=%(pki_client_database_dir)s/secmod.db
-pki_client_admin_cert=%(pki_subsystem_type)s_admin.cert
+pki_client_admin_cert=%(pki_client_dir)s/%(pki_subsystem_type)s_admin.cert
 pki_source_conf_path=/usr/share/pki/%(pki_subsystem_type)s/conf
 pki_source_setup_path=/usr/share/pki/setup
 pki_source_server_path=/usr/share/pki/server/conf
diff --git a/base/deploy/man/man5/pki_default.cfg.5 b/base/deploy/man/man5/pki_default.cfg.5
index e31002e1b79fd0f7b8364720918245a633122572..ec2379a9f55677846841344bb199904c22006154 100644
--- a/base/deploy/man/man5/pki_default.cfg.5
+++ b/base/deploy/man/man5/pki_default.cfg.5
@@ -178,9 +178,9 @@ The base DN for the internal database.  It is advised that the Certificate Serve
 .IP
 Name of the back-end database.  It is advised that the Certificate Server have its own base DN for its internal database.  If the back-end does not exist, it will be created during the running of \fBpkispawn\fP.
 .SS ISSUING CA PARAMETERS
-\x'-1'\fBpki_issuing_ca\fR
+\x'-1'\fBpki_issuing_ca_hostname, pki_issuing_ca_https_port, pki_issuing_ca_uri\fR
 .IP
-Required for installations of subordinate CA and non-CA subsystems.  This is the URI for the CA that will issue the relevant system certificates for the subsystem.  In a default install, this defaults to the CA subsystem within the same instance.  This has the format https://<ca_hostname>/<ca_https_port>.
+Hostname and port, or URI of the issuing CA.  Required for installations of subordinate CA and non-CA subsystems.  This should point to the CA that will issue the relevant system certificates for the subsystem.  In a default install, this defaults to the CA subsystem within the same instance.  The URI has the format https://<ca_hostname>:<ca_https_port>.
 
 .SS MISCELLANEOUS PARAMETERS
 \x'-1'\fBpki_restart_configured_instance\fR
diff --git a/base/deploy/man/man8/pkispawn.8 b/base/deploy/man/man8/pkispawn.8
index 312f433b8e4ab5274c50a10144285ff7b45b75d4..c5361c3b0a31aefc884e23a71f5feff96474013d 100644
--- a/base/deploy/man/man8/pkispawn.8
+++ b/base/deploy/man/man8/pkispawn.8
@@ -131,7 +131,7 @@ pki_security_domain_password=\fIpassword123\fP
 pki_security_domain_hostname=<ca_hostname>
 pki_security_domain_https_port=<ca_port>
 pki_security_domain_user=caadmin
-pki_issuing_ca=https://<ca_hostname>:<ca_port>
+pki_issuing_ca_uri=https://<ca_hostname>:<ca_port>
 
 [KRA]
 pki_import_admin_cert=False
diff --git a/base/deploy/src/pkidestroy b/base/deploy/src/pkidestroy
index edb57e9ac3472ab34b650f7ec9cdf7662e946dc6..ba52d9642731b38343a2f34280873939b9b25514 100755
--- a/base/deploy/src/pkidestroy
+++ b/base/deploy/src/pkidestroy
@@ -1,4 +1,4 @@
-#!/usr/bin/python -t
+#!/usr/bin/python -tu
 # Authors:
 #     Matthew Harmsen <mharmsen@redhat.com>
 #
@@ -94,17 +94,53 @@ def main(argv):
         'PKI Instance Removal',
         log.PKIDESTROY_EPILOG)
 
-    parser.mandatory.add_argument('-i',
+    parser.optional.add_argument('-i',
         dest='pki_deployed_instance_name',
         action='store',
-        nargs=1, required=True, metavar='<instance>',
+        nargs=1, metavar='<instance>',
         help='FORMAT:  ${pki_instance_name}')
 
     args = parser.process_command_line_arguments(argv)
 
-    # -i <instance name>
-    config.pki_deployed_instance_name =\
-        str(args.pki_deployed_instance_name).strip('[\']')
+    interactive = False
+
+    while True:
+
+        # -s <subsystem>
+        if args.pki_subsystem is None:
+            interactive = True
+            config.pki_subsystem = parser.read_text('Subsystem (CA/KRA/OCSP/TKS)',
+                options=['CA', 'KRA', 'OCSP', 'TKS'],
+                default='CA', caseSensitive=False).upper()
+        else:
+            config.pki_subsystem = str(args.pki_subsystem).strip('[\']')
+
+        # -i <instance name>
+        if args.pki_deployed_instance_name is None:
+            interactive = True
+            config.pki_deployed_instance_name = parser.read_text('Instance', default='pki-tomcat')
+        else:
+            config.pki_deployed_instance_name = str(args.pki_deployed_instance_name).strip('[\']')
+
+        if interactive:
+            print
+            parser.indent = 0
+
+            begin = parser.read_text('Begin uninstallation (Yes/No/Quit)',
+                options=['Yes', 'Y', 'No', 'N', 'Quit', 'Q'],
+                sign='?', allowEmpty=False, caseSensitive=False).lower()
+
+            print
+
+            if begin == 'q' or begin == 'quit':
+                print "Uninstallation canceled."
+                sys.exit(0)
+
+            elif begin == 'y' or begin == 'yes':
+                break
+
+        else:
+            break
 
     # verify that previously deployed instance exists
     deployed_pki_instance_path = config.pki_root_prefix +\
@@ -135,6 +171,7 @@ def main(argv):
         config.USER_DEPLOYMENT_CONFIGURATION
 
     parser.validate()
+    parser.init_config()
 
     # Enable 'pkidestroy' logging.
     config.pki_log_dir = config.pki_root_prefix +\
@@ -161,20 +198,6 @@ def main(argv):
                              extra=config.PKI_INDENTATION_LEVEL_0)
         sys.exit(1)
 
-    # NEVER print out 'sensitive' name/value pairs!!!
-    config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_default_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_web_server_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-
     # Combine the various sectional dictionaries into a PKI master dictionary
     parser.compose_pki_master_dictionary()
     config.pki_master_dict['pki_destroy_log'] = config.pki_log_dir + "/" +\
@@ -184,6 +207,8 @@ def main(argv):
     config.pki_log.debug(pkilogging.format(config.pki_master_dict),
                          extra=config.PKI_INDENTATION_LEVEL_0)
 
+    print "Uninstalling " + config.pki_subsystem + " from " + deployed_pki_instance_path + "."
+
     # Process the various "scriptlets" to remove the specified PKI subsystem.
     pki_subsystem_scriptlets = config.pki_master_dict['destroy_scriplets'].split()
     rv = 0
@@ -200,6 +225,9 @@ def main(argv):
     config.pki_log.debug(pkilogging.format(config.pki_master_dict),
                          extra=config.PKI_INDENTATION_LEVEL_0)
 
+    print
+    print "Uninstallation complete."
+
 
 # PKI Deployment Entry Point
 if __name__ == "__main__":
diff --git a/base/deploy/src/pkispawn b/base/deploy/src/pkispawn
index f64d79575000bf5c54ab5b9348cb243cce2d3b3b..f03bc15a1a5fcbbf9a730921b76e1810f480117d 100755
--- a/base/deploy/src/pkispawn
+++ b/base/deploy/src/pkispawn
@@ -1,4 +1,4 @@
-#!/usr/bin/python -t
+#!/usr/bin/python -tu
 # Authors:
 #     Matthew Harmsen <mharmsen@redhat.com>
 #
@@ -94,9 +94,9 @@ def main(argv):
         'PKI Instance Installation and Configuration',
         log.PKISPAWN_EPILOG)
 
-    parser.mandatory.add_argument('-f',
+    parser.optional.add_argument('-f',
         dest='user_deployment_cfg', action='store',
-        nargs=1, required=True, metavar='<file>',
+        nargs=1, metavar='<file>',
         help='configuration filename '
             '(MUST specify complete path)')
 
@@ -109,12 +109,112 @@ def main(argv):
     config.default_deployment_cfg = config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE
 
     # -f <user deployment config>
-    config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']')
+    if args.user_deployment_cfg is not None:
+        config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']')
 
     # -u
     config.pki_update_flag = args.pki_update_flag
 
     parser.validate()
+    interactive = False
+
+    while True:
+
+        # -s <subsystem>
+        if args.pki_subsystem is None:
+            interactive = True
+            parser.indent = 0
+
+            config.pki_subsystem = parser.read_text('Subsystem (CA/KRA/OCSP/TKS)',
+                options=['CA', 'KRA', 'OCSP', 'TKS'],
+                default='CA', caseSensitive=False).upper()
+            print
+        else:
+            config.pki_subsystem = str(args.pki_subsystem).strip('[\']')
+
+        parser.init_config()
+
+        if config.user_deployment_cfg is None:
+            interactive = True
+            parser.indent = 2
+
+            print "Tomcat:"
+            parser.read_text('Instance', 'DEFAULT', 'pki_instance_name')
+            parser.read_text('HTTP port', config.pki_subsystem, 'pki_http_port')
+            parser.read_text('Secure HTTP port', config.pki_subsystem, 'pki_https_port')
+            parser.read_text('AJP port', config.pki_subsystem, 'pki_ajp_port')
+            parser.read_text('Management port', config.pki_subsystem, 'pki_tomcat_server_port')
+            print
+
+            print "Administrator:"
+            parser.read_text('Username', config.pki_subsystem, 'pki_admin_uid')
+
+            admin_password = parser.read_password(
+                'Password', config.pki_subsystem, 'pki_admin_password',
+                verifyMessage='Verify password')
+
+            parser.set_property(config.pki_subsystem, 'pki_backup_password', admin_password)
+            parser.set_property(config.pki_subsystem, 'pki_client_database_password', admin_password)
+            parser.set_property(config.pki_subsystem, 'pki_client_pkcs12_password', admin_password)
+
+            if config.pki_master_dict['pki_import_admin_cert'] == 'True':
+                import_cert = 'Y'
+            else:
+                import_cert = 'N'
+
+            import_cert = parser.read_text('Import certificate (Yes/No)',
+                default=import_cert, options=['Yes', 'Y', 'No', 'N'],
+                sign='?', caseSensitive=False).lower()
+
+            if import_cert == 'y' or import_cert == 'yes':
+                parser.set_property(config.pki_subsystem, 'pki_import_admin_cert', 'True')
+                parser.read_text('Import certificate from', config.pki_subsystem, 'pki_admin_cert_file')
+            else:
+                parser.set_property(config.pki_subsystem, 'pki_import_admin_cert', 'False')
+
+            parser.read_text('Export certificate to', config.pki_subsystem, 'pki_client_admin_cert')
+            print
+
+            print "Directory Server:"
+            parser.read_text('Hostname', config.pki_subsystem, 'pki_ds_hostname')
+            parser.read_text('Port', config.pki_subsystem, 'pki_ds_ldap_port')
+            parser.read_text('Base DN', config.pki_subsystem, 'pki_ds_base_dn')
+            parser.read_text('Bind DN', config.pki_subsystem, 'pki_ds_bind_dn')
+            parser.read_password(
+                'Password', config.pki_subsystem, 'pki_ds_password',
+                verifyMessage='Verify password')
+            print
+
+            print "Security Domain:"
+            parser.read_text('Name', config.pki_subsystem, 'pki_security_domain_name')
+
+            if config.pki_subsystem != "CA":
+                parser.read_text('Hostname', config.pki_subsystem, 'pki_security_domain_hostname')
+                parser.read_text('Secure HTTP port', config.pki_subsystem, 'pki_security_domain_https_port')
+                parser.read_text('Username', config.pki_subsystem, 'pki_security_domain_user')
+                parser.read_password(
+                    'Password', config.pki_subsystem, 'pki_security_domain_password',
+                    verifyMessage='Verify password')
+
+            print
+
+        if interactive:
+            parser.indent = 0
+
+            begin = parser.read_text('Begin installation (Yes/No/Quit)',
+                options=['Yes', 'Y', 'No', 'N', 'Quit', 'Q'],
+                sign='?', allowEmpty=False, caseSensitive=False).lower()
+            print
+
+            if begin == 'q' or begin == 'quit':
+                print "Installation canceled."
+                sys.exit(0)
+
+            elif begin == 'y' or begin == 'yes':
+                break
+
+        else:
+            break
 
     if not os.path.exists(config.PKI_DEPLOYMENT_SOURCE_ROOT +\
                           "/" + config.pki_subsystem.lower()):
@@ -161,20 +261,6 @@ def main(argv):
                              extra=config.PKI_INDENTATION_LEVEL_0)
         sys.exit(1)
 
-    # NEVER print out 'sensitive' name/value pairs!!!
-    config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_default_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_web_server_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-
     # Read in the PKI slots configuration file.
     parser.compose_pki_slots_dictionary()
     config.pki_log.debug(log.PKI_DICTIONARY_SLOTS,
@@ -184,6 +270,7 @@ def main(argv):
 
     # Combine the various sectional dictionaries into a PKI master dictionary
     parser.compose_pki_master_dictionary()
+
     if not config.pki_update_flag:
         config.pki_master_dict['pki_spawn_log'] = config.pki_log_dir + "/" +\
                                                   config.pki_log_name
@@ -195,6 +282,8 @@ def main(argv):
     config.pki_log.debug(pkilogging.format(config.pki_master_dict),
                          extra=config.PKI_INDENTATION_LEVEL_0)
 
+    print "Installing " + config.pki_subsystem + " into " + config.pki_master_dict['pki_instance_path'] + "."
+
     # Process the various "scriptlets" to create the specified PKI subsystem.
     pki_subsystem_scriptlets = config.pki_master_dict['spawn_scriplets'].split()
     rv = 0
@@ -214,6 +303,9 @@ def main(argv):
     config.pki_log.debug(pkilogging.format(config.pki_master_dict),
                          extra=config.PKI_INDENTATION_LEVEL_0)
 
+    print
+    print "Installation complete."
+
 
 # PKI Deployment Entry Point
 if __name__ == "__main__":
diff --git a/base/deploy/src/scriptlets/infrastructure_layout.py b/base/deploy/src/scriptlets/infrastructure_layout.py
index 947fbcdfef6cbf0217a644ce2e69c9f870bcc1c8..69a905849624a43ce674eebe7624d6f8e7adf44b 100644
--- a/base/deploy/src/scriptlets/infrastructure_layout.py
+++ b/base/deploy/src/scriptlets/infrastructure_layout.py
@@ -58,8 +58,15 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.directory.create(master['pki_subsystem_registry_path'])
         util.file.copy(master['pki_default_deployment_cfg'],
                        master['pki_default_deployment_cfg_replica'])
-        util.file.copy(master['pki_user_deployment_cfg'],
-                       master['pki_user_deployment_cfg_replica'])
+
+        print "Storing deployment configuration into " + config.pki_master_dict['pki_user_deployment_cfg_replica'] + "."
+        if master['pki_user_deployment_cfg']:
+            util.file.copy(master['pki_user_deployment_cfg'],
+                           master['pki_user_deployment_cfg_replica'])
+        else:
+            with open(master['pki_user_deployment_cfg_replica'], 'w') as f:
+                config.user_config.write(f)
+
         # establish top-level infrastructure, instance, and subsystem
         # base directories and create the "registry" symbolic link that
         # the "pkidestroy" executable relies upon
diff --git a/base/deploy/src/scriptlets/pkiconfig.py b/base/deploy/src/scriptlets/pkiconfig.py
index 4a884617c7caab03159b68d4407b8897f151564c..cdd671c91d97c6cb5ff35d6c6576c766873a4303 100644
--- a/base/deploy/src/scriptlets/pkiconfig.py
+++ b/base/deploy/src/scriptlets/pkiconfig.py
@@ -180,10 +180,7 @@ pki_console_log_level = None
 
 
 # PKI Deployment Global Dictionaries
-pki_default_dict = None
-pki_web_server_dict = None
-pki_subsystem_dict = None
-pki_master_dict = None
+pki_master_dict = {}
 pki_slots_dict = None
 pki_master_jython_dict = None
 
diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py
index a7635c130bef310d70a12a00ab29aee7b4793199..4768d8af9d2307542fcd72237a0a0e6eaf3ce6ee 100644
--- a/base/deploy/src/scriptlets/pkijython.py
+++ b/base/deploy/src/scriptlets/pkijython.py
@@ -566,9 +566,7 @@ class rest_client:
                 javasystem.out.println(log.PKI_JYTHON_RESPONSE_ADMIN_CERT +\
                                        " " + admin_cert)
                 # Store the Administration Certificate in a file
-                admin_cert_file = os.path.join(
-                    master['pki_client_dir'],
-                    master['pki_client_admin_cert'])
+                admin_cert_file = master['pki_client_admin_cert']
                 admin_cert_bin_file = admin_cert_file + ".der"
                 javasystem.out.println(log.PKI_JYTHON_ADMIN_CERT_SAVE +\
                                        " " + "'" + admin_cert_file + "'")
diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py
index ba4f376daf4a26e8b4495b25f3c9dcccf66f8ed9..7f2d5859ddae59be993976f6b6f6f137cfd6bb00 100644
--- a/base/deploy/src/scriptlets/pkiparser.py
+++ b/base/deploy/src/scriptlets/pkiparser.py
@@ -22,6 +22,7 @@
 # System Imports
 import ConfigParser
 import argparse
+import getpass
 import logging
 import os
 import random
@@ -54,14 +55,15 @@ class PKIConfigParser:
 
         # Establish 'Mandatory' command-line options
         self.mandatory = self.arg_parser.add_argument_group('mandatory arguments')
-        self.mandatory.add_argument('-s',
+
+        # Establish 'Optional' command-line options
+        self.optional = self.arg_parser.add_argument_group('optional arguments')
+        self.optional.add_argument('-s',
                                dest='pki_subsystem', action='store',
                                nargs=1, choices=config.PKI_SUBSYSTEMS,
-                               required=True, metavar='<subsystem>',
+                               metavar='<subsystem>',
                                help='where <subsystem> is '
                                     'CA, KRA, OCSP, RA, TKS, or TPS')
-        # Establish 'Optional' command-line options
-        self.optional = self.arg_parser.add_argument_group('optional arguments')
         self.optional.add_argument('-h', '--help',
                               dest='help', action='help',
                               help='show this help message and exit')
@@ -77,6 +79,8 @@ class PKIConfigParser:
                           help='directory prefix to specify local directory '
                                '[TEST ONLY]')
 
+        self.indent = 0
+
     # PKI Deployment Helper Functions
     def process_command_line_arguments(self, argv):
 
@@ -84,8 +88,6 @@ class PKIConfigParser:
         args = self.arg_parser.parse_args()
 
         # Process 'Mandatory' command-line options
-        #    '-s'
-        config.pki_subsystem = str(args.pki_subsystem).strip('[\']')
 
         # Process 'Optional' command-line options
         #    '-v'
@@ -145,15 +147,63 @@ class PKIConfigParser:
             self.arg_parser.print_help()
             self.arg_parser.exit(-1);
 
-        # verify user configuration file exists
-        if not os.path.exists(config.user_deployment_cfg) or\
-            not os.path.isfile(config.user_deployment_cfg):
-            print "ERROR:  " +\
-                  log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\
-                  config.user_deployment_cfg
-            print
-            self.arg_parser.print_help()
-            self.arg_parser.exit(-1);
+        if config.user_deployment_cfg:
+            # verify user configuration file exists
+            if not os.path.exists(config.user_deployment_cfg) or\
+                not os.path.isfile(config.user_deployment_cfg):
+                print "ERROR:  " +\
+                      log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\
+                      config.user_deployment_cfg
+                print
+                parser.arg_parser.print_help()
+                parser.arg_parser.exit(-1);
+
+
+    def init_config(self):
+
+        # RESTEasy
+        resteasy_lib = subprocess.check_output(\
+            'source /etc/pki/pki.conf && echo $RESTEASY_LIB',
+            shell=True).strip()
+
+        # arch dependent libpath
+        if config.pki_architecture == 64:
+            arch_java_lib = '/usr/lib64/java'
+        else:
+            arch_java_lib = '/usr/lib/java'
+
+        if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+            default_instance_name = 'pki-tomcat'
+            default_http_port = '8080'
+            default_https_port = '8443'
+        else:
+            default_instance_name = 'pki-apache'
+            default_http_port = '80'
+            default_https_port = '443'
+
+        self.pki_config = ConfigParser.SafeConfigParser({
+            'pki_instance_name': default_instance_name,
+            'pki_http_port': default_http_port,
+            'pki_https_port': default_https_port,
+            'pki_dns_domainname': config.pki_dns_domainname,
+            'pki_subsystem': config.pki_subsystem,
+            'pki_subsystem_type': config.pki_subsystem.lower(),
+            'pki_root_prefix' : config.pki_root_prefix,
+            'resteasy_lib': resteasy_lib,
+            'arch_java_lib': arch_java_lib,
+            'home_dir': os.path.expanduser("~"),
+            'pki_hostname': config.pki_hostname})
+
+        # Make keys case-sensitive!
+        self.pki_config.optionxform = str
+
+        config.user_config = ConfigParser.SafeConfigParser()
+        config.user_config.optionxform = str
+
+        with open(config.default_deployment_cfg) as f:
+                self.pki_config.readfp(f)
+
+        self.flatten_master_dict()
 
 
     # The following code is based heavily upon
@@ -180,83 +230,124 @@ class PKIConfigParser:
         return values
 
 
+    def set_property(self, section, property, value):
+        if section != "DEFAULT" and not self.pki_config.has_section(section):
+            self.pki_config.add_section(section)
+        self.pki_config.set(section, property, value)
+        self.flatten_master_dict()
+
+        if section != "DEFAULT" and not config.user_config.has_section(section):
+            config.user_config.add_section(section)
+        config.user_config.set(section, property, value)
+
+
+    def read_text(self, message,
+        section=None, property=None, default=None,
+        options=None, sign=':', allowEmpty=True, caseSensitive=True):
+
+        if default is None and property is not None:
+            default = config.pki_master_dict[property]
+        if default:
+            message = message + ' [' + default + ']'
+        message = ' ' * self.indent + message + sign + ' '
+
+        done = False
+        while not done:
+            value = raw_input(message)
+            value = value.strip()
+
+            if len(value) == 0:  # empty value
+                if allowEmpty:
+                    value = default
+                    done = True
+                    break
+
+            else:  # non-empty value
+                if options is not None:
+                    for v in options:
+                        if caseSensitive:
+                            if v == value:
+                                done = True
+                                break
+                        else:
+                            if v.lower() == value.lower():
+                                done = True
+                                break
+                else:
+                    done = True
+                    break
+
+        if section:
+            self.set_property(section, property, value)
+
+        return value
+
+
+    def read_password(self, message, section=None, property=None,
+        verifyMessage=None):
+        message = ' ' * self.indent + message + ': '
+        verifyMessage = ' ' * self.indent + verifyMessage + ': '
+        while True:
+            password = ''
+            while len(password) == 0:
+                password = getpass.getpass(prompt=message)
+
+            verification = ''
+            while len(verification) == 0:
+                verification = getpass.getpass(prompt=verifyMessage)
+
+            if password == verification:
+                break
+            else:
+                print ' ' * self.indent  + 'Passwords do not match.'
+
+        if section:
+            self.set_property(section, property, password)
+
+        return password
+
     def read_pki_configuration_file(self):
         "Read configuration file sections into dictionaries"
         rv = 0
         try:
-            if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-                default_instance_name = 'pki-tomcat'
-                default_http_port = '8080'
-                default_https_port = '8443'
-            else:
-                default_instance_name = 'pki-apache'
-                default_http_port = '80'
-                default_https_port = '443'
+            if config.user_deployment_cfg:
+                print 'Loading deployment configuration from ' + config.user_deployment_cfg + '.'
+                self.pki_config.read([config.user_deployment_cfg])
 
-            # RESTEasy
-            resteasy_lib = subprocess.check_output(\
-                'source /etc/pki/pki.conf && echo $RESTEASY_LIB',
-                shell=True).strip()
-
-            # arch dependent libpath
-            if config.pki_architecture == 64:
-                arch_java_lib = '/usr/lib64/java'
-            else:
-                arch_java_lib = '/usr/lib/java'
-
-            predefined_dict = {'pki_instance_name': default_instance_name,
-                               'pki_http_port': default_http_port,
-                               'pki_https_port': default_https_port,
-                               'pki_dns_domainname': config.pki_dns_domainname,
-                               'pki_subsystem' : config.pki_subsystem,
-                               'pki_subsystem_type': config.pki_subsystem.lower(),
-                               'pki_root_prefix' : config.pki_root_prefix,
-                               'resteasy_lib': resteasy_lib,
-                               'arch_java_lib': arch_java_lib,
-                               'home_dir': os.path.expanduser("~"),
-                               'pki_hostname': config.pki_hostname}
-
-            self.pki_config = ConfigParser.SafeConfigParser(predefined_dict)
-            # Make keys case-sensitive!
-            self.pki_config.optionxform = str
-            self.pki_config.read([
-                config.default_deployment_cfg,
-                config.user_deployment_cfg])
-            config.pki_default_dict = dict(self.pki_config.items('DEFAULT'))
-            pkilogging.sensitive_parameters = config.pki_default_dict['sensitive_parameters'].split()
-            if config.pki_subsystem == "CA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('CA'))
-            elif config.pki_subsystem == "KRA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('KRA'))
-            elif config.pki_subsystem == "OCSP":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('OCSP'))
-            elif config.pki_subsystem == "RA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Apache'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('RA'))
-            elif config.pki_subsystem == "TKS":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('TKS'))
-            elif config.pki_subsystem == "TPS":
-                config.pki_web_server_dict = dict(self.pki_config.items('Apache'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('TPS'))
-            # Insert empty record into dictionaries for "pretty print" statements
-            #     NEVER print "sensitive" key value pairs!!!
-            config.pki_default_dict[0] = None
-            config.pki_web_server_dict[0] = None
-            config.pki_subsystem_dict[0] = None
         except ConfigParser.ParsingError, err:
             print err
             rv = err
         return rv
 
 
+    def flatten_master_dict(self):
+        config.pki_master_dict.update(__name__="PKI Master Dictionary")
+
+        default_dict = dict(self.pki_config.items('DEFAULT'))
+        default_dict[0] = None
+        config.pki_master_dict.update(default_dict)
+
+        web_server_dict = None
+        if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+            if self.pki_config.has_section('Tomcat'):
+                web_server_dict = dict(self.pki_config.items('Tomcat'))
+        else:
+            if self.pki_config.has_section('Apache'):
+                web_server_dict = dict(self.pki_config.items('Apache'))
+
+        if web_server_dict:
+            web_server_dict[0] = None
+            config.pki_master_dict.update(web_server_dict)
+
+        if self.pki_config.has_section(config.pki_subsystem):
+            subsystem_dict = dict(self.pki_config.items(config.pki_subsystem))
+            subsystem_dict[0] = None
+            config.pki_master_dict.update(subsystem_dict)
+
+
     def compose_pki_master_dictionary(self):
         "Create a single master PKI dictionary from the sectional dictionaries"
         try:
-            config.pki_master_dict = dict()
             # 'pkispawn'/'pkirespawn'/'pkidestroy' name/value pairs
             config.pki_master_dict['pki_deployment_executable'] =\
                 config.pki_deployment_executable
@@ -280,12 +371,10 @@ class PKIConfigParser:
                 random.randint(pin_low, pin_high)
             config.pki_master_dict['pki_client_pin'] =\
                 random.randint(pin_low, pin_high)
-            # Configuration file name/value pairs
-            #     NEVER add "sensitive" key value pairs to the master dictionary!!!
-            config.pki_master_dict.update(config.pki_default_dict)
-            config.pki_master_dict.update(config.pki_web_server_dict)
-            config.pki_master_dict.update(config.pki_subsystem_dict)
-            config.pki_master_dict.update(__name__="PKI Master Dictionary")
+
+            self.flatten_master_dict()
+
+            pkilogging.sensitive_parameters = config.pki_master_dict['sensitive_parameters'].split()
 
             # PKI Target (slot substitution) name/value pairs
             config.pki_master_dict['pki_target_cs_cfg'] =\
@@ -783,11 +872,7 @@ class PKIConfigParser:
                     "https" + "://" +\
                     config.pki_master_dict['pki_security_domain_hostname'] + ":" +\
                     config.pki_master_dict['pki_security_domain_https_port']
-                if not len(config.pki_master_dict['pki_issuing_ca']):
-                    # Guess that it is the same as the
-                    # config.pki_master_dict['pki_security_domain_uri']
-                    config.pki_master_dict['pki_issuing_ca'] =\
-                        config.pki_master_dict['pki_security_domain_uri']
+
             elif config.str2bool(config.pki_master_dict['pki_external']):
                 # External CA
                 config.pki_master_dict['pki_security_domain_type'] = "new"
-- 
1.7.12.1

