diff --git a/.github/workflows/ca-clone-replicated-ds-test.yml b/.github/workflows/ca-clone-replicated-ds-test.yml index bd959401288..fd71b254b62 100644 --- a/.github/workflows/ca-clone-replicated-ds-test.yml +++ b/.github/workflows/ca-clone-replicated-ds-test.yml @@ -115,6 +115,27 @@ jobs: --pkcs12 $SHARED/ca-certs.p12 \ --password Secret.123 + - name: Configure connection to CA database + run: | + # store DS password + docker exec secondary pki-server password-add \ + --password Secret.123 \ + internaldb + + # configure DS connection params + docker exec secondary pki-server ca-db-config-mod \ + --hostname secondaryds.example.com \ + --port 3389 \ + --secure false \ + --auth BasicAuth \ + --bindDN "cn=Directory Manager" \ + --bindPWPrompt internaldb \ + --database ca \ + --baseDN dc=ca,dc=pki,dc=example,dc=com \ + --multiSuffix false \ + --maxConns 15 \ + --minConns 3 + # https://github.com/dogtagpki/389-ds-base/wiki/Configuring-DS-Replication-with-DS-Tools - name: Preparing DS backend run: | @@ -126,13 +147,7 @@ jobs: backend suffix list # create backend for CA in secondary DS - docker exec secondaryds dsconf \ - -D "cn=Directory Manager" \ - -w Secret.123 \ - ldap://secondaryds.example.com:3389 \ - backend create \ - --suffix=dc=ca,dc=pki,dc=example,dc=com \ - --be-name=ca + docker exec secondary pki-server ca-db-create -v - name: Enable replication on primary DS run: | diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CADBCLI.java b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CADBCLI.java index 56b8d337507..fd78a5fd86d 100644 --- a/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CADBCLI.java +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/cli/CADBCLI.java @@ -20,6 +20,7 @@ import org.dogtagpki.cli.CLI; import org.dogtagpki.server.cli.SubsystemDBAccessCLI; +import org.dogtagpki.server.cli.SubsystemDBCreateCLI; import org.dogtagpki.server.cli.SubsystemDBEmptyCLI; import org.dogtagpki.server.cli.SubsystemDBIndexCLI; import org.dogtagpki.server.cli.SubsystemDBInfoCLI; @@ -37,6 +38,7 @@ public CADBCLI(CLI parent) { super("db", "CA database management commands", parent); addModule(new SubsystemDBInfoCLI(this)); + addModule(new SubsystemDBCreateCLI(this)); addModule(new SubsystemDBInitCLI(this)); addModule(new SubsystemDBEmptyCLI(this)); addModule(new SubsystemDBRemoveCLI(this)); diff --git a/base/server/python/pki/server/cli/db.py b/base/server/python/pki/server/cli/db.py index 96a83234ac6..32a274dfb1c 100644 --- a/base/server/python/pki/server/cli/db.py +++ b/base/server/python/pki/server/cli/db.py @@ -214,6 +214,7 @@ def __init__(self, parent): self.parent = parent self.add_module(SubsystemDBConfigCLI(self)) self.add_module(SubsystemDBInfoCLI(self)) + self.add_module(SubsystemDBCreateCLI(self)) self.add_module(SubsystemDBInitCLI(self)) self.add_module(SubsystemDBEmptyCLI(self)) self.add_module(SubsystemDBRemoveCLI(self)) @@ -616,6 +617,82 @@ def execute(self, argv): subsystem.run(cmd, as_current_user=as_current_user) +class SubsystemDBCreateCLI(pki.cli.CLI): + ''' + Create {subsystem} database + ''' + + help = '''\ + Usage: pki-server {subsystem}-db-create [OPTIONS] + + -i, --instance Instance ID (default: pki-tomcat) + -v, --verbose Run in verbose mode. + --debug Run in debug mode. + --help Show help message. + ''' + + def __init__(self, parent): + super().__init__( + 'create', + inspect.cleandoc(self.__class__.__doc__).format( + subsystem=parent.parent.name.upper())) + + self.parent = parent + + def print_help(self): + print(textwrap.dedent(self.__class__.help).format( + subsystem=self.parent.parent.name)) + + def execute(self, argv): + try: + opts, _ = getopt.gnu_getopt(argv, 'i:v', [ + 'instance=', + 'verbose', 'debug', 'help']) + + except getopt.GetoptError as e: + logger.error(e) + self.print_help() + sys.exit(1) + + instance_name = 'pki-tomcat' + subsystem_name = self.parent.parent.name + + for o, a in opts: + if o in ('-i', '--instance'): + instance_name = a + + elif o in ('-v', '--verbose'): + logging.getLogger().setLevel(logging.INFO) + + elif o == '--debug': + logging.getLogger().setLevel(logging.DEBUG) + + elif o == '--help': + self.print_help() + sys.exit() + + else: + logger.error('Invalid option: %s', o) + self.print_help() + sys.exit(1) + + instance = pki.server.instance.PKIServerFactory.create(instance_name) + if not instance.exists(): + logger.error('Invalid instance: %s', instance_name) + sys.exit(1) + + instance.load() + + subsystem = instance.get_subsystem(subsystem_name) + + if not subsystem: + logger.error('No %s subsystem in instance %s', + subsystem_name.upper(), instance_name) + sys.exit(1) + + subsystem.create_database() + + class SubsystemDBInitCLI(pki.cli.CLI): ''' Initialize {subsystem} database @@ -627,7 +704,6 @@ class SubsystemDBInitCLI(pki.cli.CLI): -i, --instance Instance ID (default: pki-tomcat) --skip-config Skip DS server configuration. --skip-schema Skip DS schema setup. - --create-backend Create DS backend. --skip-base Skip base entry setup. --skip-containers Skip container entries setup. -v, --verbose Run in verbose mode. @@ -651,7 +727,7 @@ def execute(self, argv): try: opts, _ = getopt.gnu_getopt(argv, 'i:v', [ 'instance=', 'skip-config', 'skip-schema', - 'create-backend', 'skip-base', 'skip-containers', + 'skip-base', 'skip-containers', 'verbose', 'debug', 'help']) except getopt.GetoptError as e: @@ -664,7 +740,6 @@ def execute(self, argv): skip_config = False skip_schema = False - create_backend = False skip_base = False skip_containers = False @@ -678,9 +753,6 @@ def execute(self, argv): elif o == '--skip-schema': skip_schema = True - elif o == '--create-backend': - create_backend = True - elif o == '--skip-base': skip_base = True @@ -719,7 +791,6 @@ def execute(self, argv): subsystem.init_database( skip_config=skip_config, skip_schema=skip_schema, - create_backend=create_backend, skip_base=skip_base, skip_containers=skip_containers) diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py index 5b3c8b993b1..b90a8e4f209 100644 --- a/base/server/python/pki/server/deployment/__init__.py +++ b/base/server/python/pki/server/deployment/__init__.py @@ -1524,6 +1524,10 @@ def setup_database(self, subsystem, master_config): else: logger.info('Reusing replicated database') + if config.str2bool(self.mdict['pki_ds_create_new_db']): + logger.info('Creating database') + subsystem.create_database() + logger.info('Initializing database') # In most cases, we want to replicate the schema and therefore not add it here. @@ -1538,8 +1542,6 @@ def setup_database(self, subsystem, master_config): config.str2bool(self.mdict['pki_clone_setup_replication']) and \ config.str2bool(self.mdict['pki_clone_replicate_schema']) - create_backend = config.str2bool(self.mdict['pki_ds_create_new_db']) - # When cloning a subsystem without setting up the replication agreements, # the database is a subtree of an existing tree and is already replicated, # so there is no need to set up the base entry. @@ -1552,7 +1554,6 @@ def setup_database(self, subsystem, master_config): subsystem.init_database( skip_schema=skip_schema, - create_backend=create_backend, skip_base=skip_base, skip_containers=skip_containers) diff --git a/base/server/python/pki/server/subsystem.py b/base/server/python/pki/server/subsystem.py index f29bb55f6e6..01c2099ae25 100644 --- a/base/server/python/pki/server/subsystem.py +++ b/base/server/python/pki/server/subsystem.py @@ -1160,11 +1160,22 @@ def import_ldif(self, bind_dn, bind_password, filename): logger.debug('Command: %s', ' '.join(cmd)) subprocess.check_call(cmd) + def create_database(self): + + cmd = [self.name + '-db-create'] + + if logger.isEnabledFor(logging.DEBUG): + cmd.append('--debug') + + elif logger.isEnabledFor(logging.INFO): + cmd.append('--verbose') + + self.run(cmd) + def init_database( self, skip_config=False, skip_schema=False, - create_backend=False, skip_base=False, skip_containers=False, as_current_user=False): @@ -1177,9 +1188,6 @@ def init_database( if skip_schema: cmd.append('--skip-schema') - if create_backend: - cmd.append('--create-backend') - if skip_base: cmd.append('--skip-base') diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCLI.java index 248ce9c6db6..db6661b20e9 100644 --- a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCLI.java +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCLI.java @@ -29,6 +29,7 @@ public SubsystemDBCLI(CLI parent) { super("db", parent.name.toUpperCase() + " database management commands", parent); addModule(new SubsystemDBInfoCLI(this)); + addModule(new SubsystemDBCreateCLI(this)); addModule(new SubsystemDBInitCLI(this)); addModule(new SubsystemDBEmptyCLI(this)); addModule(new SubsystemDBRemoveCLI(this)); diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCreateCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCreateCLI.java new file mode 100644 index 00000000000..c433cc8505d --- /dev/null +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBCreateCLI.java @@ -0,0 +1,89 @@ +// +// Copyright Red Hat, Inc. +// +// SPDX-License-Identifier: GPL-2.0-or-later +// +package org.dogtagpki.server.cli; + +import org.apache.commons.cli.CommandLine; +import org.dogtagpki.cli.CLI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netscape.cms.servlet.csadmin.LDAPConfigurator; +import com.netscape.cmscore.apps.EngineConfig; +import com.netscape.cmscore.ldapconn.LDAPConfig; +import com.netscape.cmscore.ldapconn.LDAPConnectionConfig; +import com.netscape.cmscore.ldapconn.LdapAuthInfo; +import com.netscape.cmscore.ldapconn.LdapBoundConnection; +import com.netscape.cmscore.ldapconn.LdapConnInfo; +import com.netscape.cmscore.ldapconn.PKISocketConfig; +import com.netscape.cmscore.ldapconn.PKISocketFactory; +import com.netscape.cmsutil.ldap.LDAPUtil; +import com.netscape.cmsutil.password.PasswordStore; +import com.netscape.cmsutil.password.PasswordStoreConfig; + +/** + * @author Endi S. Dewata + */ +public class SubsystemDBCreateCLI extends SubsystemCLI { + + public static final Logger logger = LoggerFactory.getLogger(SubsystemDBCreateCLI.class); + + public SubsystemDBCreateCLI(CLI parent) { + super("create", "Create " + parent.getParent().getName().toUpperCase() + " database", parent); + } + + @Override + public void createOptions() { + options.addOption("v", "verbose", false, "Run in verbose mode."); + options.addOption(null, "debug", false, "Run in debug mode."); + options.addOption(null, "help", false, "Show help message."); + } + + @Override + public void execute(CommandLine cmd) throws Exception { + + initializeTomcatJSS(); + String subsystem = parent.getParent().getName(); + EngineConfig cs = getEngineConfig(subsystem); + cs.load(); + + LDAPConfig ldapConfig = cs.getInternalDBConfig(); + String database = ldapConfig.getDatabase(); + String baseDN = ldapConfig.getBaseDN(); + + logger.info("Creating database " + database); + + PasswordStoreConfig psc = cs.getPasswordStoreConfig(); + PasswordStore passwordStore = PasswordStore.create(psc); + + LDAPConnectionConfig connConfig = ldapConfig.getConnectionConfig(); + + LdapConnInfo connInfo = new LdapConnInfo(connConfig); + LdapAuthInfo authInfo = getAuthInfo(passwordStore, connInfo, ldapConfig); + + PKISocketConfig socketConfig = cs.getSocketConfig(); + + PKISocketFactory socketFactory = new PKISocketFactory(); + socketFactory.setSecure(connInfo.getSecure()); + if (authInfo.getAuthType() == LdapAuthInfo.LDAP_AUTHTYPE_SSLCLIENTAUTH) { + socketFactory.setClientCertNickname(authInfo.getClientCertNickname()); + } + socketFactory.init(socketConfig); + + LdapBoundConnection conn = new LdapBoundConnection(socketFactory, connInfo, authInfo); + LDAPConfigurator ldapConfigurator = new LDAPConfigurator(conn, ldapConfig); + + try { + String databaseDN = "cn=" + LDAPUtil.escapeRDNValue(database) + ",cn=ldbm database,cn=plugins,cn=config"; + ldapConfigurator.createBackendEntry(databaseDN, database, baseDN); + + String mappingDN = "cn=\"" + baseDN + "\",cn=mapping tree,cn=config"; + ldapConfigurator.createMappingEntry(mappingDN, database, baseDN); + + } finally { + conn.disconnect(); + } + } +} diff --git a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBInitCLI.java b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBInitCLI.java index c5a20161a2a..5c861abeab8 100644 --- a/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBInitCLI.java +++ b/base/server/src/main/java/org/dogtagpki/server/cli/SubsystemDBInitCLI.java @@ -20,7 +20,6 @@ import com.netscape.cmscore.ldapconn.LdapConnInfo; import com.netscape.cmscore.ldapconn.PKISocketConfig; import com.netscape.cmscore.ldapconn.PKISocketFactory; -import com.netscape.cmsutil.ldap.LDAPUtil; import com.netscape.cmsutil.password.PasswordStore; import com.netscape.cmsutil.password.PasswordStoreConfig; @@ -48,7 +47,6 @@ public void createOptions() { options.addOption(null, "skip-config", false, "Skip DS server configuration"); options.addOption(null, "skip-schema", false, "Skip DS schema setup"); - options.addOption(null, "create-backend", false, "Create DS backend"); options.addOption(null, "skip-base", false, "Skip base entry setup"); options.addOption(null, "skip-containers", false, "Skip container entries setup"); @@ -100,14 +98,6 @@ public void execute(CommandLine cmd) throws Exception { ldapConfigurator.setupSchema(); } - if (cmd.hasOption("create-backend")) { - String databaseDN = "cn=" + LDAPUtil.escapeRDNValue(database) + ",cn=ldbm database, cn=plugins, cn=config"; - ldapConfigurator.createBackendEntry(databaseDN, database, baseDN); - - String mappingDN = "cn=\"" + baseDN + "\",cn=mapping tree, cn=config"; - ldapConfigurator.createMappingEntry(mappingDN, database, baseDN); - } - if (!cmd.hasOption("skip-base")) { ldapConfigurator.createBaseEntry(baseDN); }