URL: https://github.com/freeipa/freeipa/pull/245 Author: frasertweedale Title: #245: Allow full customisability of IPA CA subject DN Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/245/head:pr245 git checkout pr245
From 315c3c6d95977847afffc94d6e3ace03d3f101e0 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Fri, 11 Nov 2016 18:54:01 +1000 Subject: [PATCH 01/12] Refactor and relocate set_subject_base_in_config Refactor set_subject_base_in_config to use api.Backend.ldap2 instead of a manually created LDAP connection. Also rename the function to have a more accurate name, and move it to 'ipaserver.install.ca' to avoid cyclic import (we will eventually need to use it from within that module). Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/install/ca.py | 9 +++++++++ ipaserver/install/server/install.py | 24 +----------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index 4f64d99..820c6ee 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -48,6 +48,15 @@ external_ca_file = None +def set_subject_base_in_config(subject_base): + entry_attrs = api.Backend.ldap2.get_ipa_config() + entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] + try: + api.Backend.ldap2.update_entry(entry_attrs) + except errors.EmptyModlist: + pass + + def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index fc319d9..36bbb4b 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -16,7 +16,6 @@ from ipalib.install import certmonger, sysrestore from ipapython import ipautil -from ipapython.dn import DN from ipapython.ipa_log_manager import root_logger from ipapython.ipautil import ( format_netloc, ipa_generate_password, run, user_input) @@ -40,7 +39,6 @@ IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address, is_ipa_configured, load_pkcs12, read_password, verify_fqdn, update_hosts_file) -from ipaserver.plugins.ldap2 import ldap2 if six.PY3: unicode = str @@ -242,25 +240,6 @@ def check_dirsrv(unattended): raise ScriptError(msg) -def set_subject_in_config(realm_name, dm_password, suffix, subject_base): - ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % ( - installutils.realm_to_serverid(realm_name) - ) - try: - conn = ldap2(api, ldap_uri=ldapuri) - conn.connect(bind_dn=DN(('cn', 'directory manager')), - bind_pw=dm_password) - except errors.ExecutionError as e: - root_logger.critical("Could not connect to the Directory Server " - "on %s" % realm_name) - raise e - entry_attrs = conn.get_ipa_config() - if 'ipacertificatesubjectbase' not in entry_attrs: - entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] - conn.update_entry(entry_attrs) - conn.disconnect() - - def common_cleanup(func): def decorated(installer): success = False @@ -848,8 +827,7 @@ def install(installer): os.chmod(paths.IPA_CA_CRT, 0o644) ca_db.publish_ca_cert(paths.IPA_CA_CRT) - set_subject_in_config(realm_name, dm_password, - ipautil.realm_to_suffix(realm_name), options.subject) + ca.set_subject_base_in_config(options.subject_base) # Apply any LDAP updates. Needs to be done after the configuration file # is created. DS is restarted in the process. From 8a7e9b17c493a980f8405a3e4ce18bd735973594 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 16 Nov 2016 19:31:19 +1000 Subject: [PATCH 02/12] installutils: remove hardcoded subject DN assumption `installutils.load_external_cert` assumes that the IPA CA subject DN is `CN=Certificate Authority, {subject_base}`. In preparation for full customisability of IPA CA subject DN, push this assumption out of this function to call sites (which will be updated in a subsequent commit). Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/install/ca.py | 4 +++- ipaserver/install/installutils.py | 7 ++++--- ipaserver/install/ipa_cacert_manage.py | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index 820c6ee..56f6692 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -109,7 +109,9 @@ def install_check(standalone, replica_config, options): "--external-ca.") external_cert_file, external_ca_file = installutils.load_external_cert( - options.external_cert_files, options.subject) + options.external_cert_files, + DN(('CN', 'Certificate Authority'), options.subject) + ) elif options.external_ca: if cainstance.is_step_one_done(): raise ScriptError( diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index e7fd69f..21cf4c1 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -1095,7 +1095,8 @@ def check_entropy(): except ValueError as e: root_logger.debug("Invalid value in %s %s", paths.ENTROPY_AVAIL, e) -def load_external_cert(files, subject_base): + +def load_external_cert(files, ca_subject): """ Load and verify external CA certificate chain from multiple files. @@ -1103,7 +1104,7 @@ def load_external_cert(files, subject_base): chain formats. :param files: Names of files to import - :param subject_base: Subject name base for IPA certificates + :param ca_subject: IPA CA subject DN :returns: Temporary file with the IPA CA certificate and temporary file with the external CA certificate chain """ @@ -1117,7 +1118,7 @@ def load_external_cert(files, subject_base): except RuntimeError as e: raise ScriptError(str(e)) - ca_subject = DN(('CN', 'Certificate Authority'), subject_base) + ca_subject = DN(ca_subject) ca_nickname = None cache = {} for nickname, _trust_flags in nssdb.list_certs(): diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py index 5a278f4..4082dfa 100644 --- a/ipaserver/install/ipa_cacert_manage.py +++ b/ipaserver/install/ipa_cacert_manage.py @@ -192,8 +192,6 @@ def renew_external_step_2(self, ca, old_cert_der): options = self.options conn = api.Backend.ldap2 - cert_file, ca_file = installutils.load_external_cert( - options.external_cert_files, x509.subject_base()) old_cert_obj = x509.load_certificate(old_cert_der, x509.DER) old_der_subject = x509.get_der_subject(old_cert_der, x509.DER) @@ -202,6 +200,11 @@ def renew_external_step_2(self, ca, old_cert_der): serialization.PublicFormat.SubjectPublicKeyInfo ) + cert_file, ca_file = installutils.load_external_cert( + options.external_cert_files, + DN(('CN', 'Certificate Authority'), x509.subject_base()) + ) + with open(cert_file.name) as f: new_cert_data = f.read() new_cert_der = x509.normalize_certificate(new_cert_data) From 662206740a54cd361d2ee18ba5d24588b374080d Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 16 Nov 2016 19:59:58 +1000 Subject: [PATCH 03/12] installer: rename --subject to --subject-base The --subject option is actually used to provide the "subject base". We are also going to add an option for fully specifying the IPA CA subject DN in a subsequent commit. So to avoid confusion, rename --subject to --subject-base, retaining --subject as a deprecated alias. Part of: https://fedorahosted.org/freeipa/ticket/2614 --- install/tools/ipa-ca-install | 4 ++-- install/tools/man/ipa-server-install.1 | 4 ++-- ipaserver/install/ca.py | 17 +++++++++-------- ipaserver/install/server/install.py | 16 ++++++++-------- ipaserver/install/server/replicainstall.py | 4 ++-- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 88939f9..819e7a9 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -169,7 +169,7 @@ def install_replica(safe_options, options, filename): options.domain_name = config.domain_name options.dm_password = config.dirman_password options.host_name = config.host_name - options.subject = config.subject_base + options.subject_base = config.subject_base if os.path.exists(cafile): options.ca_cert_file = cafile else: @@ -198,7 +198,7 @@ def install_master(safe_options, options): options.domain_name = api.env.domain options.dm_password = dm_password options.host_name = api.env.host - options.subject = subject_base + options.subject_base = subject_base ca.install_check(True, None, options) ca.install(True, None, options) diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 index 69316fb..e7f3ff4 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -129,8 +129,8 @@ Name of the Kerberos KDC SSL certificate to install \fB\-\-ca\-cert\-file\fR=\fIFILE\fR File containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC certificates. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. Use this option if the CA certificate is not present in the certificate files. .TP -\fB\-\-subject\fR=\fISUBJECT\fR -The certificate subject base (default O=REALM.NAME) +\fB\-\-subject\-base\fR=\fISUBJECT\fR +The subject base for certificates issued by IPA (default O=REALM.NAME) .TP \fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm. diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index 56f6692..b5b2f2a 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -66,7 +66,7 @@ def install_check(standalone, replica_config, options): realm_name = options.realm_name host_name = options.host_name - subject_base = options.subject + subject_base = options.subject_base if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': @@ -110,7 +110,7 @@ def install_check(standalone, replica_config, options): external_cert_file, external_ca_file = installutils.load_external_cert( options.external_cert_files, - DN(('CN', 'Certificate Authority'), options.subject) + DN(('CN', 'Certificate Authority'), options.subject_base) ) elif options.external_ca: if cainstance.is_step_one_done(): @@ -164,7 +164,7 @@ def install_step_0(standalone, replica_config, options): host_name = options.host_name if replica_config is None: - subject_base = options.subject + subject_base = options.subject_base ca_signing_algorithm = options.ca_signing_algorithm if options.external_ca: @@ -236,7 +236,7 @@ def install_step_1(standalone, replica_config, options): realm_name = options.realm_name host_name = options.host_name - subject_base = options.subject + subject_base = options.subject_base basedn = ipautil.realm_to_suffix(realm_name) @@ -379,14 +379,15 @@ def external_cert_files(self, value): if any(not os.path.isabs(path) for path in value): raise ValueError("must use an absolute path") - subject = knob( + subject_base = knob( str, None, description="The certificate subject base (default O=<realm-name>)", + cli_deprecated_names=['--subject'], ) - subject = master_install_only(subject) + subject_base = master_install_only(subject_base) - @subject.validator - def subject(self, value): + @subject_base.validator + def subject_base(self, value): v = unicode(value, 'utf-8') if any(ord(c) < 0x20 for c in v): raise ValueError("must not contain control characters") diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 36bbb4b..6b13bec 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -464,8 +464,8 @@ def install_check(installer): else: realm_name = options.realm_name.upper() - if not options.subject: - options.subject = DN(('O', realm_name)) + if not options.subject_base: + options.subject_base = DN(('O', realm_name)) if options.http_cert_files: if options.http_pin is None: @@ -725,7 +725,7 @@ def install(installer): ds.create_instance(realm_name, host_name, domain_name, dm_password, dirsrv_pkcs12_info, idstart=options.idstart, idmax=options.idmax, - subject_base=options.subject, + subject_base=options.subject_base, hbac_allow=not options.no_hbac_allow) else: ds = dsinstance.DsInstance(fstore=fstore, @@ -735,7 +735,7 @@ def install(installer): ds.create_instance(realm_name, host_name, domain_name, dm_password, idstart=options.idstart, idmax=options.idmax, - subject_base=options.subject, + subject_base=options.subject_base, hbac_allow=not options.no_hbac_allow) ntpinstance.ntp_ldap_enable(host_name, ds.suffix, realm_name) @@ -747,7 +747,7 @@ def install(installer): installer._ds = ds ds.init_info( realm_name, host_name, domain_name, dm_password, - options.subject, 1101, 1100, None) + options.subject_base, 1101, 1100, None) if setup_ca: if not options.external_cert_files and options.external_ca: @@ -781,7 +781,7 @@ def install(installer): dm_password, master_password, setup_pkinit=not options.no_pkinit, pkcs12_info=pkinit_pkcs12_info, - subject_base=options.subject) + subject_base=options.subject_base) # restart DS to enable ipa-pwd-extop plugin print("Restarting directory server to enable password extension plugin") @@ -811,13 +811,13 @@ def install(installer): if options.http_cert_files: http.create_instance( realm_name, host_name, domain_name, - pkcs12_info=http_pkcs12_info, subject_base=options.subject, + pkcs12_info=http_pkcs12_info, subject_base=options.subject_base, auto_redirect=not options.no_ui_redirect, ca_is_configured=setup_ca) else: http.create_instance( realm_name, host_name, domain_name, - subject_base=options.subject, + subject_base=options.subject_base, auto_redirect=not options.no_ui_redirect, ca_is_configured=setup_ca) tasks.restore_context(paths.CACHE_IPA_SESSIONS) diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 6e986f7..1d8cd20 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -797,7 +797,7 @@ def install_check(installer): if ca_enabled: options.realm_name = config.realm_name options.host_name = config.host_name - options.subject = config.subject_base + options.subject_base = config.subject_base ca.install_check(False, config, options) if kra_enabled: @@ -1204,7 +1204,7 @@ def promote_check(installer): if ca_enabled: options.realm_name = config.realm_name options.host_name = config.host_name - options.subject = config.subject_base + options.subject_base = config.subject_base ca.install_check(False, config, options) if kra_enabled: From b4da6e53edbb8d869cd5f7b06959b34e799fcfb5 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 16 Nov 2016 20:39:23 +1000 Subject: [PATCH 04/12] Extract function for computing default subject base Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/install/cainstance.py | 8 ++++---- ipaserver/install/dsinstance.py | 3 ++- ipaserver/install/installutils.py | 4 ++++ ipaserver/install/krainstance.py | 8 ++++---- ipaserver/install/server/install.py | 2 +- ipaserver/install/server/replicainstall.py | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index c7e81f0..4f01f83 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -352,10 +352,10 @@ def configure_instance(self, host_name, dm_password, admin_password, self.clone = True self.master_host = master_host self.master_replication_port = master_replication_port - if subject_base is None: - self.subject_base = DN(('O', self.realm)) - else: - self.subject_base = subject_base + + self.subject_base = \ + subject_base or installutils.default_subject_base(self.realm) + if ca_signing_algorithm is None: self.ca_signing_algorithm = 'SHA256withRSA' else: diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index bcfcb05..978ca55 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -1251,7 +1251,8 @@ def _request_service_keytab(self): replacevars=vardict) def __get_ds_cert(self): - subject = self.subject_base or DN(('O', self.realm)) + subject = self.subject_base \ + or installutils.default_subject_base(self.realm) nssdb_dir = config_dirname(self.serverid) db = certs.CertDB(self.realm, nssdir=nssdb_dir, subject_base=subject) db.create_from_cacert(paths.IPA_CA_CRT) diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 21cf4c1..ca7a5d6 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -1476,3 +1476,7 @@ def restart_dirsrv(instance_name="", capture_output=True): capture_output=capture_output, wait=True, ldapi=True) api.Backend.ldap2.connect() + + +def default_subject_base(realm_name): + return DN(('O', realm_name)) diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py index 554811c..1d9c2b7 100644 --- a/ipaserver/install/krainstance.py +++ b/ipaserver/install/krainstance.py @@ -90,10 +90,10 @@ def configure_instance(self, realm_name, host_name, dm_password, if self.pkcs12_info is not None or promote: self.clone = True self.master_host = master_host - if subject_base is None: - self.subject_base = DN(('O', self.realm)) - else: - self.subject_base = subject_base + + self.subject_base = \ + subject_base or installutils.default_subject_base(realm_name) + self.realm = realm_name self.suffix = ipautil.realm_to_suffix(realm_name) diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 6b13bec..aae8d36 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -465,7 +465,7 @@ def install_check(installer): realm_name = options.realm_name.upper() if not options.subject_base: - options.subject_base = DN(('O', realm_name)) + options.subject_base = installutils.default_subject_base(realm_name) if options.http_cert_files: if options.http_pin is None: diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 1d8cd20..c084d23 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -79,7 +79,7 @@ def install_http_certs(host_name, realm_name, subject_base): principal = 'HTTP/%s@%s' % (host_name, realm_name) # Obtain certificate for the HTTP service nssdir = certs.NSS_DIR - subject = subject_base or DN(('O', realm_name)) + subject = subject_base or installutils.default_subject_base(realm_name) db = certs.CertDB(realm_name, nssdir=nssdir, subject_base=subject) db.request_service_cert('Server-Cert', principal, host_name, True) From 0a084a04b788c90d06d43e0ca1d7b8ed7cc8c978 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 30 Nov 2016 16:26:15 +1000 Subject: [PATCH 05/12] ipa-ca-install: add missing --subject-base option Part of: https://fedorahosted.org/freeipa/ticket/2614 --- install/tools/ipa-ca-install | 12 ++++++++---- ipaserver/install/ca.py | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 819e7a9..253c27f 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -73,6 +73,11 @@ def parse_options(): help="Signing algorithm of the IPA CA certificate") parser.add_option("-P", "--principal", dest="principal", sensitive=True, default=None, help="User allowed to manage replicas") + parser.add_option("--subject-base", dest="subject_base", + default=None, + help=( + "The certificate subject base " + "(default O=<realm-name>)")) options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) @@ -191,14 +196,13 @@ def install_master(safe_options, options): if dm_password is None: sys.exit("Directory Manager password required") - config = api.Command['config_show']()['result'] - subject_base = config['ipacertificatesubjectbase'][0] - options.realm_name = api.env.realm options.domain_name = api.env.domain options.dm_password = dm_password options.host_name = api.env.host - options.subject_base = subject_base + + if not options.subject_base: + options.subject_base = installutils.default_subject_base(api.env.realm) ca.install_check(True, None, options) ca.install(True, None, options) diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index b5b2f2a..7b67110 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -15,6 +15,7 @@ from ipalib.install import certstore from ipalib.install.service import enroll_only, master_install_only, replica_install_only +from ipaserver.install import sysupgrade from ipapython.install import typing from ipapython.install.core import knob from ipaserver.install import (cainstance, @@ -212,6 +213,13 @@ def install_step_0(standalone, replica_config, options): ra_only = not replica_config.setup_ca promote = options.promote + # if upgrading from CA-less to CA-ful, need to rewrite + # subject_base configuration + # + set_subject_base_in_config(subject_base) + sysupgrade.set_upgrade_state( + 'certmap.conf', 'subject_base', str(subject_base)) + ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, host_name=host_name) ca.configure_instance(host_name, dm_password, dm_password, From de06f00027ad367a50c39a51c10b6b9f09384afe Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 14 Dec 2016 13:23:11 +1000 Subject: [PATCH 06/12] dsinstance: extract function for writing certmap.conf For full customisability of the IPA CA subject DN, we will need the ability to update DS `certmap.conf' when upgrading a deployment from CA-less to CA-ful. Extract the existing behaviour, which is private to DsInstance, to the `write_certmap_conf' top-level function. Also update `certmap.conf.template' for substition of the whole CA subject DN (not just the subject base). Part of: https://fedorahosted.org/freeipa/ticket/2614 --- install/share/certmap.conf.template | 2 +- ipaserver/install/dsinstance.py | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/install/share/certmap.conf.template b/install/share/certmap.conf.template index e76bf3c..d59b095 100644 --- a/install/share/certmap.conf.template +++ b/install/share/certmap.conf.template @@ -41,6 +41,6 @@ certmap default default #default:InitFn <Init function's name> default:DNComps default:FilterComps uid -certmap ipaca CN=Certificate Authority,$SUBJECT_BASE +certmap ipaca $ISSUER_DN ipaca:CmapLdapAttr seeAlso ipaca:verifycert on diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 978ca55..27a43de 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -921,11 +921,8 @@ def __create_indices(self): self._ldap_mod("indices.ldif") def __certmap_conf(self): - shutil.copyfile( - os.path.join(paths.USR_SHARE_IPA_DIR, "certmap.conf.template"), - os.path.join(config_dirname(self.serverid), "certmap.conf")) - installutils.update_file(config_dirname(self.serverid) + "certmap.conf", - '$SUBJECT_BASE', str(self.subject_base)) + ca_subject = 'CN=Certificate Authority,' + str(self.subject_base) + write_certmap_conf(self.realm, ca_subject) sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', @@ -1286,3 +1283,14 @@ def __get_ds_cert(self): # check for open secure port 636 from now on self.open_ports.append(636) + + +def write_certmap_conf(realm, ca_subject): + """(Re)write certmap.conf with given CA subject DN.""" + serverid = installutils.realm_to_serverid(realm) + ds_dirname = config_dirname(serverid) + certmap_filename = os.path.join(ds_dirname, "certmap.conf") + shutil.copyfile( + os.path.join(paths.USR_SHARE_IPA_DIR, "certmap.conf.template"), + certmap_filename) + installutils.update_file(certmap_filename, '$ISSUER_DN', str(ca_subject)) From a2457c178cf0e44035a0327e75de019ebdec829e Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Mon, 19 Dec 2016 14:31:14 +1000 Subject: [PATCH 07/12] Reuse self.api when executing ca_enabled_check The ca_enabled_check function is a wrapper around api.Command.ca_is_enabled. When using remote_api (e.g. during installer), ca_enabled_check invokes the *global* api instead of the remote_api. Update ca_enabled_check to explicitly receive an api object from the caller and invoke Command.ca_is_enabled through it. Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/plugins/ca.py | 12 ++++++------ ipaserver/plugins/cert.py | 16 ++++++++-------- ipaserver/plugins/certprofile.py | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py index 2510a79..51ea648 100644 --- a/ipaserver/plugins/ca.py +++ b/ipaserver/plugins/ca.py @@ -190,7 +190,7 @@ class ca_find(LDAPSearch): ) def execute(self, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) result = super(ca_find, self).execute(*keys, **options) for entry in result['result']: set_certificate_attrs(entry, options, want_cert=False) @@ -213,7 +213,7 @@ class ca_show(LDAPRetrieve): ) def execute(self, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) result = super(ca_show, self).execute(*keys, **options) set_certificate_attrs(result['result'], options) return result @@ -229,7 +229,7 @@ class ca_add(LDAPCreate): ) def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) if not ldap.can_add(dn[1:]): raise errors.ACIError( info=_("Insufficient 'add' privilege for entry '%s'.") % dn) @@ -272,7 +272,7 @@ class ca_del(LDAPDelete): msg_summary = _('Deleted CA "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) if keys[0] == IPA_CA_CN: raise errors.ProtectedEntryError( @@ -294,7 +294,7 @@ class ca_mod(LDAPUpdate): msg_summary = _('Modified CA "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) if 'rename' in options or 'cn' in entry_attrs: if keys[0] == IPA_CA_CN: @@ -310,7 +310,7 @@ class CAQuery(LDAPQuery): has_output = output.standard_value def execute(self, cn, **options): - ca_enabled_check() + ca_enabled_check(self.api) ca_id = self.api.Command.ca_show(cn)['result']['ipacaid'][0] with self.api.Backend.ra_lightweight_ca as ca_api: diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py index 81872cf..9bc5779 100644 --- a/ipaserver/plugins/cert.py +++ b/ipaserver/plugins/cert.py @@ -196,8 +196,8 @@ def normalize_serial_number(num): return unicode(num) -def ca_enabled_check(): - if not api.Command.ca_is_enabled()['result']: +def ca_enabled_check(_api): + if not _api.Command.ca_is_enabled()['result']: raise errors.NotFound(reason=_('CA is not configured')) def caacl_check(principal_type, principal, ca, profile_id): @@ -538,7 +538,7 @@ def get_args(self): yield arg def execute(self, csr, all=False, raw=False, **kw): - ca_enabled_check() + ca_enabled_check(self.api) ldap = self.api.Backend.ldap2 realm = unicode(self.api.env.realm) @@ -904,7 +904,7 @@ class cert_status(Retrieve, BaseCertMethod, VirtualCommand): operation = "certificate status" def execute(self, request_id, **kw): - ca_enabled_check() + ca_enabled_check(self.api) self.check_access() # Dogtag requests are uniquely identified by their number; @@ -1012,7 +1012,7 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): def execute(self, serial_number, all=False, raw=False, no_members=False, **options): - ca_enabled_check() + ca_enabled_check(self.api) # Dogtag lightweight CAs have shared serial number domain, so # we don't tell Dogtag the issuer (but we check the cert after). @@ -1075,7 +1075,7 @@ def get_options(self): yield option def execute(self, serial_number, **kw): - ca_enabled_check() + ca_enabled_check(self.api) # Make sure that the cert specified by issuer+serial exists. # Will raise NotFound if it does not. @@ -1111,7 +1111,7 @@ class cert_remove_hold(PKQuery, CertMethod, VirtualCommand): operation = "certificate remove hold" def execute(self, serial_number, **kw): - ca_enabled_check() + ca_enabled_check(self.api) # Make sure that the cert specified by issuer+serial exists. # Will raise NotFound if it does not. @@ -1318,7 +1318,7 @@ def _ca_search(self, all, raw, pkey_only, sizelimit, exactly, **options): complete = bool(ra_options) try: - ca_enabled_check() + ca_enabled_check(self.api) except errors.NotFound: if ra_options: raise diff --git a/ipaserver/plugins/certprofile.py b/ipaserver/plugins/certprofile.py index 2bd3311..4eab09f 100644 --- a/ipaserver/plugins/certprofile.py +++ b/ipaserver/plugins/certprofile.py @@ -75,14 +75,14 @@ class must be used. register = Registry() -def ca_enabled_check(): +def ca_enabled_check(_api): """Raise NotFound if CA is not enabled. This function is defined in multiple plugins to avoid circular imports (cert depends on certprofile, so we cannot import cert here). """ - if not api.Command.ca_is_enabled()['result']: + if not _api.Command.ca_is_enabled()['result']: raise errors.NotFound(reason=_('CA is not configured')) @@ -191,7 +191,7 @@ class certprofile_find(LDAPSearch): ) def execute(self, *args, **kwargs): - ca_enabled_check() + ca_enabled_check(self.api) return super(certprofile_find, self).execute(*args, **kwargs) @@ -206,7 +206,7 @@ class certprofile_show(LDAPRetrieve): ) def execute(self, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) result = super(certprofile_show, self).execute(*keys, **options) if 'out' in options: @@ -233,7 +233,7 @@ class certprofile_import(LDAPCreate): PROFILE_ID_PATTERN = re.compile('^profileId=([a-zA-Z]\w*)', re.MULTILINE) def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) context.profile = options['file'] match = self.PROFILE_ID_PATTERN.search(options['file']) @@ -271,7 +271,7 @@ class certprofile_del(LDAPDelete): msg_summary = _('Deleted profile "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) if keys[0] in [p.profile_id for p in INCLUDED_PROFILES]: raise errors.ValidationError(name='profile_id', @@ -304,7 +304,7 @@ class certprofile_mod(LDAPUpdate): ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - ca_enabled_check() + ca_enabled_check(self.api) # Once a profile id is set it cannot be changed if 'cn' in entry_attrs: raise errors.ProtectedEntryError(label='certprofile', key=keys[0], From 360e57ed1e67928bef1bea6c225a66c5beb9b100 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 16 Nov 2016 20:49:36 +1000 Subject: [PATCH 08/12] Allow full customisability of IPA CA subject DN Currently only the "subject base" of the IPA CA subject DN can be customised, via the installer's --subject-base option. The RDN "CN=Certificate Authority" is appended to form the subject DN, and this composition is widely assumed. Some administrators need more control over the CA subject DN, especially to satisfy expectations of external CAs when the IPA CA is to be externally signed. This patch adds full customisability of the CA subject DN. Specifically: - Add the --ca-subject option for specifying the full IPA CA subject DN. Defaults to "CN=Certificate Authority, O=$SUBJECT_BASE". - ipa-ca-install, when installing a CA in a previous CA-less topology, updates DS certmap.conf with the new new CA subject DN. - DsInstance.find_subject_base no longer looks in certmap.conf, because the CA subject DN can be unrelated to the subject base. Fixes: https://fedorahosted.org/freeipa/ticket/2614 --- install/tools/ipa-ca-install | 9 ++- install/tools/man/ipa-ca-install.1 | 6 ++ install/tools/man/ipa-server-install.1 | 3 + ipaserver/install/ca.py | 123 ++++++++++++++++++++--------- ipaserver/install/cainstance.py | 14 ++-- ipaserver/install/certs.py | 20 +++-- ipaserver/install/dsinstance.py | 67 ++++++++-------- ipaserver/install/installutils.py | 4 + ipaserver/install/ipa_cacert_manage.py | 4 +- ipaserver/install/krainstance.py | 7 +- ipaserver/install/server/__init__.py | 3 +- ipaserver/install/server/install.py | 8 +- ipaserver/install/server/replicainstall.py | 19 +++-- 13 files changed, 189 insertions(+), 98 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 253c27f..63dbb7d 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -78,6 +78,11 @@ def parse_options(): help=( "The certificate subject base " "(default O=<realm-name>)")) + parser.add_option("--ca-subject", dest="ca_subject", + default=None, + help=( + "The CA certificate subject DN " + "(default CN=Certificate Authority,O=<realm-name>)")) options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) @@ -174,7 +179,6 @@ def install_replica(safe_options, options, filename): options.domain_name = config.domain_name options.dm_password = config.dirman_password options.host_name = config.host_name - options.subject_base = config.subject_base if os.path.exists(cafile): options.ca_cert_file = cafile else: @@ -203,6 +207,9 @@ def install_master(safe_options, options): if not options.subject_base: options.subject_base = installutils.default_subject_base(api.env.realm) + if not options.ca_subject: + options.ca_subject = installutils.default_ca_subject_dn( + options.subject_base) ca.install_check(True, None, options) ca.install(True, None, options) diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1 index aa18698..16e5431 100644 --- a/install/tools/man/ipa-ca-install.1 +++ b/install/tools/man/ipa-ca-install.1 @@ -46,6 +46,12 @@ Type of the external CA. Possible values are "generic", "ms-cs". Default value i \fB\-\-external\-cert\-file\fR=\fIFILE\fR File containing the IPA CA certificate and the external CA certificate chain. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. .TP +\fB\-\-ca\-subject\fR=\fISUBJECT\fR +The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME) +.TP +\fB\-\-subject\-base\fR=\fISUBJECT\fR +The subject base for certificates issued by IPA (default O=REALM.NAME) +.TP \fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm. .TP diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 index e7f3ff4..9bab143 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -129,6 +129,9 @@ Name of the Kerberos KDC SSL certificate to install \fB\-\-ca\-cert\-file\fR=\fIFILE\fR File containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC certificates. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. Use this option if the CA certificate is not present in the certificate files. .TP +\fB\-\-ca\-subject\fR=\fISUBJECT\fR +The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME) +.TP \fB\-\-subject\-base\fR=\fISUBJECT\fR The subject base for certificates issued by IPA (default O=REALM.NAME) .TP diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index 7b67110..8475ed3 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -13,6 +13,7 @@ import six +from ipalib.constants import IPA_CA_CN from ipalib.install import certstore from ipalib.install.service import enroll_only, master_install_only, replica_install_only from ipaserver.install import sysupgrade @@ -28,7 +29,7 @@ from ipaplatform.paths import paths from ipaserver.install import installutils, certs from ipaserver.install.replication import replica_conn_check -from ipalib import api, x509 +from ipalib import api, errors, x509 from ipapython.dn import DN from ipapython.ipa_log_manager import root_logger @@ -37,18 +38,53 @@ if six.PY3: unicode = str -VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c', - 'serialnumber', 'l', 'title', 'sn', 'givenname', - 'initials', 'generationqualifier', 'dc', 'mail', - 'uid', 'postaladdress', 'postalcode', 'postofficebox', - 'houseidentifier', 'e', 'street', 'pseudonym', - 'incorporationlocality', 'incorporationstate', - 'incorporationcountry', 'businesscategory'] +VALID_SUBJECT_BASE_ATTRS = { + 'st', 'o', 'ou', 'dnqualifier', 'c', 'serialnumber', 'l', 'title', 'sn', + 'givenname', 'initials', 'generationqualifier', 'dc', 'mail', 'uid', + 'postaladdress', 'postalcode', 'postofficebox', 'houseidentifier', 'e', + 'street', 'pseudonym', 'incorporationlocality', 'incorporationstate', + 'incorporationcountry', 'businesscategory', +} +VALID_SUBJECT_ATTRS = {'cn'} | VALID_SUBJECT_BASE_ATTRS external_cert_file = None external_ca_file = None +def _subject_validator(valid_attrs, value): + v = unicode(value, 'utf-8') + if any(ord(c) < 0x20 for c in v): + raise ValueError("must not contain control characters") + if '&' in v: + raise ValueError("must not contain an ampersand (\"&\")") + try: + dn = DN(v) + for rdn in dn: + if rdn.attr.lower() not in valid_attrs: + raise ValueError("invalid attribute: \"%s\"" % rdn.attr) + except ValueError as e: + raise ValueError("invalid subject base format: %s" % e) + + +def lookup_ca_subject(api, subject_base): + dn = DN(('cn', IPA_CA_CN), api.env.container_ca, api.env.basedn) + try: + # we do not use api.Command.ca_show because it attempts to + # talk to the CA (to read certificate / chain), but the RA + # backend may be unavailable (ipa-replica-install) or unusable + # due to RA Agent cert not yet created (ipa-ca-install). + ca_subject = api.Backend.ldap2.get_entry(dn)['ipacasubjectdn'][0] + except errors.NotFound: + # if the entry doesn't exist, we are dealing with a pre-v4.4 + # installation, where the default CA subject was always based + # on the subject_base. + # + # installutils.default_ca_subject_dn is NOT used here in + # case the default changes in the future. + ca_subject = DN(('CN', 'Certificate Authority'), subject_base) + return six.text_type(ca_subject) + + def set_subject_base_in_config(subject_base): entry_attrs = api.Backend.ldap2.get_ipa_config() entry_attrs['ipacertificatesubjectbase'] = [str(subject_base)] @@ -62,12 +98,23 @@ def install_check(standalone, replica_config, options): global external_cert_file global external_ca_file - if replica_config is not None and not replica_config.setup_ca: - return - realm_name = options.realm_name host_name = options.host_name - subject_base = options.subject_base + + if replica_config is None: + options._subject_base = options.subject_base + options._ca_subject = options.ca_subject + else: + # during replica install, this gets invoked before local DS is + # available, so use the remote api. + _api = api if standalone else options._remote_api + + # for replica-install the knobs cannot be written, hence leading '_' + options._subject_base = six.text_type(replica_config.subject_base) + options._ca_subject = lookup_ca_subject(_api, options._subject_base) + + if replica_config is not None and not replica_config.setup_ca: + return if replica_config is not None: if standalone and api.env.ra_plugin == 'selfsign': @@ -110,9 +157,7 @@ def install_check(standalone, replica_config, options): "--external-ca.") external_cert_file, external_ca_file = installutils.load_external_cert( - options.external_cert_files, - DN(('CN', 'Certificate Authority'), options.subject_base) - ) + options.external_cert_files, options._ca_subject) elif options.external_ca: if cainstance.is_step_one_done(): raise ScriptError( @@ -132,8 +177,9 @@ def install_check(standalone, replica_config, options): if standalone: dirname = dsinstance.config_dirname( installutils.realm_to_serverid(realm_name)) - cadb = certs.CertDB(realm_name, subject_base=subject_base) - dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base) + cadb = certs.CertDB(realm_name, subject_base=options._subject_base) + dsdb = certs.CertDB( + realm_name, nssdir=dirname, subject_base=options._subject_base) for db in (cadb, dsdb): for nickname, _trust_flags in db.list_certs(): @@ -147,8 +193,8 @@ def install_check(standalone, replica_config, options): if not cert: continue subject = DN(x509.load_certificate(cert).subject) - if subject in (DN('CN=Certificate Authority', subject_base), - DN('CN=IPA RA', subject_base)): + if subject in (DN(options._ca_subject), + DN('CN=IPA RA', options._subject_base)): raise ScriptError( "Certificate with subject %s is present in %s, " "cannot continue." % (subject, db.secdir)) @@ -163,10 +209,10 @@ def install_step_0(standalone, replica_config, options): realm_name = options.realm_name dm_password = options.dm_password host_name = options.host_name + ca_subject = options._ca_subject + subject_base = options._subject_base if replica_config is None: - subject_base = options.subject_base - ca_signing_algorithm = options.ca_signing_algorithm if options.external_ca: ca_type = options.external_ca_type @@ -198,8 +244,6 @@ def install_step_0(standalone, replica_config, options): cafile, replica_config.dirman_password) - subject_base = replica_config.subject_base - ca_signing_algorithm = None ca_type = None csr_file = None @@ -214,16 +258,18 @@ def install_step_0(standalone, replica_config, options): promote = options.promote # if upgrading from CA-less to CA-ful, need to rewrite - # subject_base configuration + # certmap.conf and subject_base configuration # set_subject_base_in_config(subject_base) sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', str(subject_base)) + dsinstance.write_certmap_conf(realm_name, ca_subject) ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, host_name=host_name) ca.configure_instance(host_name, dm_password, dm_password, subject_base=subject_base, + subject=ca_subject, ca_signing_algorithm=ca_signing_algorithm, ca_type=ca_type, csr_file=csr_file, @@ -244,8 +290,7 @@ def install_step_1(standalone, replica_config, options): realm_name = options.realm_name host_name = options.host_name - subject_base = options.subject_base - + subject_base = options._subject_base basedn = ipautil.realm_to_suffix(realm_name) ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, host_name=host_name) @@ -396,18 +441,20 @@ def external_cert_files(self, value): @subject_base.validator def subject_base(self, value): - v = unicode(value, 'utf-8') - if any(ord(c) < 0x20 for c in v): - raise ValueError("must not contain control characters") - if '&' in v: - raise ValueError("must not contain an ampersand (\"&\")") - try: - dn = DN(v) - for rdn in dn: - if rdn.attr.lower() not in VALID_SUBJECT_ATTRS: - raise ValueError("invalid attribute: \"%s\"" % rdn.attr) - except ValueError as e: - raise ValueError("invalid subject base format: %s" % e) + _subject_validator(VALID_SUBJECT_BASE_ATTRS, value) + + ca_subject = knob( + str, None, + description=( + "The CA certificate subject DN " + "(default CN=Certificate Authority,O=<realm-name>)" + ), + ) + ca_subject = master_install_only(ca_subject) + + @ca_subject.validator + def ca_subject(self, value): + _subject_validator(VALID_SUBJECT_ATTRS, value) ca_signing_algorithm = knob( CASigningAlgorithm, None, diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index 4f01f83..3462618 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -330,7 +330,8 @@ def configure_instance(self, host_name, dm_password, admin_password, pkcs12_info=None, master_host=None, csr_file=None, cert_file=None, cert_chain_file=None, master_replication_port=None, - subject_base=None, ca_signing_algorithm=None, + subject_base=None, subject=None, + ca_signing_algorithm=None, ca_type=None, ra_p12=None, ra_only=False, promote=False, use_ldaps=False): """Create a CA instance. @@ -355,6 +356,8 @@ def configure_instance(self, host_name, dm_password, admin_password, self.subject_base = \ subject_base or installutils.default_subject_base(self.realm) + self.subject = \ + subject or installutils.default_ca_subject_dn(self.subject_base) if ca_signing_algorithm is None: self.ca_signing_algorithm = 'SHA256withRSA' @@ -514,8 +517,9 @@ def __spawn_instance(self): str(DN(('cn', self.fqdn), self.subject_base))) config.set("CA", "pki_audit_signing_subject_dn", str(DN(('cn', 'CA Audit'), self.subject_base))) - config.set("CA", "pki_ca_signing_subject_dn", - str(DN(('cn', 'Certificate Authority'), self.subject_base))) + config.set( + "CA", "pki_ca_signing_subject_dn", + str(self.subject)) # Certificate nicknames config.set("CA", "pki_subsystem_nickname", "subsystemCert cert-pki-ca") @@ -701,7 +705,7 @@ def __create_ca_agent(self): userCertificate=[cert_data], description=['2;%s;%s;%s' % ( cert.serial, - DN(('CN', 'Certificate Authority'), self.subject_base), + DN(self.subject), DN(('CN', 'IPA RA'), self.subject_base))]) conn.add_entry(entry) @@ -754,7 +758,7 @@ def __import_ca_chain(self): # Ok, now we have all the certificates in certs, walk through it # and pull out each certificate and add it to our database - ca_dn = DN(('CN','Certificate Authority'), self.subject_base) + ca_dn = DN(self.subject) for cert in certlist: try: chain_fd, chain_name = tempfile.mkstemp() diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py index 02b03d4..444f371 100644 --- a/ipaserver/install/certs.py +++ b/ipaserver/install/certs.py @@ -71,9 +71,19 @@ class CertDB(object): This class knows IPA-specific details such as nssdir location, or the CA cert name. + + ``subject_base`` + Realm subject base DN. This argument is required when creating + server or object signing certs. + ``ca_subject`` + IPA CA subject DN. This argument is required when importing + CA certificates into the certificate database. + """ # TODO: Remove all selfsign code - def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None): + def __init__( + self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, + subject_base=None, ca_subject=None): self.nssdb = NSSDatabase(nssdir) self.secdir = nssdir @@ -92,15 +102,13 @@ def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_b self.certreq_fname = None self.certder_fname = None self.host_name = host_name + self.ca_subject = ca_subject self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError as e: raise RuntimeError("Unable to determine the current directory: %s" % str(e)) - if not subject_base: - self.subject_base = DN(('O', 'IPA')) - self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024" @@ -119,6 +127,7 @@ def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_b else: self.fstore = sysrestore.FileStore(paths.SYSRESTORE) + ca_subject = ipautil.dn_attribute_property('_ca_subject') subject_base = ipautil.dn_attribute_property('_subject_base') def __del__(self): @@ -252,13 +261,12 @@ def load_cacert(self, cacert_fname, trust_flags): certs = fd.read() fd.close() - ca_dn = DN(('CN','Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) _rdn, subject_dn = get_cert_nickname(cert) - if subject_dn == ca_dn: + if subject_dn == self.ca_subject: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 27a43de..cfc2823 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -241,6 +241,7 @@ def __init__(self, realm_name=None, domain_name=None, fstore=None, self.dercert = None self.idstart = None self.idmax = None + self.subject = None self.subject_base = None self.open_ports = [] self.run_init_memberof = True @@ -301,7 +302,8 @@ def __common_post_setup(self): self.step("configuring directory to start on boot", self.__enable) def init_info(self, realm_name, fqdn, domain_name, dm_password, - subject_base, idstart, idmax, pkcs12_info, ca_file=None): + subject_base, subject, + idstart, idmax, pkcs12_info, ca_file=None): self.realm = realm_name.upper() self.serverid = installutils.realm_to_serverid(self.realm) self.suffix = ipautil.realm_to_suffix(self.realm) @@ -309,6 +311,7 @@ def init_info(self, realm_name, fqdn, domain_name, dm_password, self.dm_password = dm_password self.domain = domain_name self.subject_base = subject_base + self.subject = subject self.idstart = idstart self.idmax = idmax self.pkcs12_info = pkcs12_info @@ -320,11 +323,13 @@ def init_info(self, realm_name, fqdn, domain_name, dm_password, def create_instance(self, realm_name, fqdn, domain_name, dm_password, pkcs12_info=None, - idstart=1100, idmax=999999, subject_base=None, + idstart=1100, idmax=999999, + subject_base=None, subject=None, hbac_allow=True, ca_file=None): self.init_info( realm_name, fqdn, domain_name, dm_password, - subject_base, idstart, idmax, pkcs12_info, ca_file=ca_file) + subject_base, subject, + idstart, idmax, pkcs12_info, ca_file=ca_file) self.__common_setup() self.step("restarting directory server", self.__restart_instance) @@ -358,8 +363,9 @@ def enable_ssl(self): self.start_creation(runtime=10) def create_replica(self, realm_name, master_fqdn, fqdn, - domain_name, dm_password, subject_base, api, - pkcs12_info=None, ca_file=None, + domain_name, dm_password, + subject_base, subject, + api, pkcs12_info=None, ca_file=None, ca_is_configured=None, promote=False): # idstart and idmax are configured so that the range is seen as # depleted by the DNA plugin and the replica will go and get a @@ -374,6 +380,7 @@ def create_replica(self, realm_name, master_fqdn, fqdn, domain_name=domain_name, dm_password=dm_password, subject_base=subject_base, + subject=subject, idstart=idstart, idmax=idmax, pkcs12_info=pkcs12_info, @@ -778,7 +785,12 @@ def generate_random(self): def __enable_ssl(self): dirname = config_dirname(self.serverid) - dsdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) + dsdb = certs.CertDB( + self.realm, + nssdir=dirname, + subject_base=self.subject_base, + ca_subject=self.subject, + ) if self.pkcs12_info: if self.ca_is_configured: trust_flags = 'CT,C,C' @@ -921,8 +933,7 @@ def __create_indices(self): self._ldap_mod("indices.ldif") def __certmap_conf(self): - ca_subject = 'CN=Certificate Authority,' + str(self.subject_base) - write_certmap_conf(self.realm, ca_subject) + write_certmap_conf(self.realm, self.subject) sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', @@ -1064,7 +1075,12 @@ def add_ca_cert(self, cacert_fname, cacert_name=''): self.stop() dirname = config_dirname(installutils.realm_to_serverid(self.realm)) - certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) + certdb = certs.CertDB( + self.realm, + nssdir=dirname, + subject_base=self.subject_base, + ca_subject=self.subject, + ) if not cacert_name or len(cacert_name) == 0: cacert_name = "Imported CA" # we can't pass in the nickname, so we set the instance variable @@ -1163,8 +1179,7 @@ def find_subject_base(self): Try to find the current value of certificate subject base. 1) Look in sysupgrade first 2) If no value is found there, look in DS (start DS if necessary) - 3) Last resort, look in the certmap.conf itself - 4) If all fails, log loudly and return None + 3) If all fails, log loudly and return None Note that this method can only be executed AFTER the ipa server is configured, the api is initialized elsewhere and @@ -1206,27 +1221,6 @@ def find_subject_base(self): root_logger.error('Cannot connect to DS to find certificate ' 'subject base: %s', e) - if not subject_base: - root_logger.debug('Unable to find certificate subject base in DS') - root_logger.debug('Trying to find certificate subject base in ' - 'certmap.conf') - - certmap_dir = config_dirname( - installutils.realm_to_serverid(api.env.realm) - ) - try: - with open(os.path.join(certmap_dir, 'certmap.conf')) as f: - for line in f: - if line.startswith('certmap ipaca'): - subject_base = line.strip().split(',')[-1] - root_logger.debug( - 'Found certificate subject base in certmap.conf: ' - '%s', subject_base) - - except IOError as e: - root_logger.error('Cannot open certmap.conf to find certificate ' - 'subject base: %s', e.strerror) - if subject_base: return subject_base @@ -1248,10 +1242,13 @@ def _request_service_keytab(self): replacevars=vardict) def __get_ds_cert(self): - subject = self.subject_base \ - or installutils.default_subject_base(self.realm) nssdb_dir = config_dirname(self.serverid) - db = certs.CertDB(self.realm, nssdir=nssdb_dir, subject_base=subject) + db = certs.CertDB( + self.realm, + nssdir=nssdb_dir, + subject_base=self.subject_base, + ca_subject=self.subject, + ) db.create_from_cacert(paths.IPA_CA_CRT) db.request_service_cert(self.nickname, self.principal, self.fqdn) db.create_pin_file() diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index ca7a5d6..0d8a574 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -1480,3 +1480,7 @@ def restart_dirsrv(instance_name="", capture_output=True): def default_subject_base(realm_name): return DN(('O', realm_name)) + + +def default_ca_subject_dn(subject_base): + return DN(('CN', 'Certificate Authority'), subject_base) diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py index 4082dfa..1d1ae2f 100644 --- a/ipaserver/install/ipa_cacert_manage.py +++ b/ipaserver/install/ipa_cacert_manage.py @@ -201,9 +201,7 @@ def renew_external_step_2(self, ca, old_cert_der): ) cert_file, ca_file = installutils.load_external_cert( - options.external_cert_files, - DN(('CN', 'Certificate Authority'), x509.subject_base()) - ) + options.external_cert_files, DN(old_cert_obj.subject)) with open(cert_file.name) as f: new_cert_data = f.read() diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py index 1d9c2b7..1f38c86 100644 --- a/ipaserver/install/krainstance.py +++ b/ipaserver/install/krainstance.py @@ -77,7 +77,8 @@ def __init__(self, realm): def configure_instance(self, realm_name, host_name, dm_password, admin_password, pkcs12_info=None, master_host=None, - subject_base=None, ra_only=False, promote=False): + subject_base=None, subject=None, + ra_only=False, promote=False): """Create a KRA instance. To create a clone, pass in pkcs12_info. @@ -93,6 +94,8 @@ def configure_instance(self, realm_name, host_name, dm_password, self.subject_base = \ subject_base or installutils.default_subject_base(realm_name) + self.subject = \ + subject or installutils.default_ca_subject_dn(self.subject_base) self.realm = realm_name self.suffix = ipautil.realm_to_suffix(realm_name) @@ -307,7 +310,7 @@ def __create_kra_agent(self): userCertificate=[cert_data], description=['2;%s;%s;%s' % ( cert.serial, - DN(('CN', 'Certificate Authority'), self.subject_base), + DN(self.subject), DN(('CN', 'IPA RA'), self.subject_base))]) conn.add_entry(entry) diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py index 28cdd06..86cb4a9 100644 --- a/ipaserver/install/server/__init__.py +++ b/ipaserver/install/server/__init__.py @@ -573,7 +573,8 @@ class ServerReplicaInstall(ServerReplicaInstallInterface): Server replica installer """ - subject = None + subject_base = None + ca_subject = None admin_password = knob( bases=ServerReplicaInstallInterface.admin_password, diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index aae8d36..496ff13 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -467,6 +467,10 @@ def install_check(installer): if not options.subject_base: options.subject_base = installutils.default_subject_base(realm_name) + if not options.ca_subject: + options.ca_subject = \ + installutils.default_ca_subject_dn(options.subject_base) + if options.http_cert_files: if options.http_pin is None: options.http_pin = installutils.read_password( @@ -726,6 +730,7 @@ def install(installer): dm_password, dirsrv_pkcs12_info, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject_base, + subject=options.ca_subject, hbac_allow=not options.no_hbac_allow) else: ds = dsinstance.DsInstance(fstore=fstore, @@ -736,6 +741,7 @@ def install(installer): dm_password, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject_base, + subject=options.ca_subject, hbac_allow=not options.no_hbac_allow) ntpinstance.ntp_ldap_enable(host_name, ds.suffix, realm_name) @@ -747,7 +753,7 @@ def install(installer): installer._ds = ds ds.init_info( realm_name, host_name, domain_name, dm_password, - options.subject_base, 1101, 1100, None) + options.subject_base, options.ca_subject, 1101, 1100, None) if setup_ca: if not options.external_cert_files and options.external_ca: diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index c084d23..7f65bac 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -79,8 +79,7 @@ def install_http_certs(host_name, realm_name, subject_base): principal = 'HTTP/%s@%s' % (host_name, realm_name) # Obtain certificate for the HTTP service nssdir = certs.NSS_DIR - subject = subject_base or installutils.default_subject_base(realm_name) - db = certs.CertDB(realm_name, nssdir=nssdir, subject_base=subject) + db = certs.CertDB(realm_name, nssdir=nssdir, subject_base=subject_base) db.request_service_cert('Server-Cert', principal, host_name, True) @@ -95,6 +94,11 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, pkcs12_info = make_pkcs12_info(config.dir, "dscert.p12", "dirsrv_pin.txt") + if ca_is_configured: + ca_subject = ca.lookup_ca_subject(remote_api, config.subject_base) + else: + ca_subject = installutils.default_ca_subject_dn(config.subject_base) + ds = dsinstance.DsInstance( config_ldif=options.dirsrv_config_file) ds.create_replica( @@ -104,6 +108,7 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, domain_name=config.domain_name, dm_password=config.dirman_password, subject_base=config.subject_base, + subject=ca_subject, pkcs12_info=pkcs12_info, ca_is_configured=ca_is_configured, ca_file=ca_file, @@ -704,6 +709,10 @@ def install_check(installer): raise RuntimeError("CA cert file is not available. Please run " "ipa-replica-prepare to create a new replica file.") + # look up CA subject name (needed for DS certmap.conf) + options.ca_subject = unicode( + DN(x509.load_certificate_from_file(cafile).subject)) + for pkcs12_name, pin_name in (('dscert.p12', 'dirsrv_pin.txt'), ('httpcert.p12', 'http_pin.txt')): pkcs12_info = make_pkcs12_info(config.dir, pkcs12_name, pin_name) @@ -738,6 +747,7 @@ def install_check(installer): confdir=paths.ETC_IPA, ldap_uri=ldapuri) remote_api.finalize() + installer._remote_api = remote_api conn = remote_api.Backend.ldap2 replman = None try: @@ -797,7 +807,6 @@ def install_check(installer): if ca_enabled: options.realm_name = config.realm_name options.host_name = config.host_name - options.subject_base = config.subject_base ca.install_check(False, config, options) if kra_enabled: @@ -856,7 +865,6 @@ def install_check(installer): installer._ca_enabled = ca_enabled installer._kra_enabled = kra_enabled installer._ca_file = cafile - installer._remote_api = remote_api installer._fstore = fstore installer._sstore = sstore @@ -1068,6 +1076,7 @@ def promote_check(installer): ldap_uri=ldapuri, xmlrpc_uri=xmlrpc_uri) remote_api.finalize() + installer._remote_api = remote_api check_remote_version(remote_api) @@ -1204,7 +1213,6 @@ def promote_check(installer): if ca_enabled: options.realm_name = config.realm_name options.host_name = config.host_name - options.subject_base = config.subject_base ca.install_check(False, config, options) if kra_enabled: @@ -1264,7 +1272,6 @@ def promote_check(installer): installer._fstore = fstore installer._sstore = sstore installer._config = config - installer._remote_api = remote_api installer._add_to_ipaservers = add_to_ipaservers installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info From 62ae9a88710de223edda948653e45e276884c828 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Thu, 17 Nov 2016 09:26:02 +1000 Subject: [PATCH 09/12] Indicate that ca subject / subject base uses LDAP RDN order Update man pages and help output to indicate that --subject-base and --ca-subject options interpret their arguments in LDAP order. Fixes: https://fedorahosted.org/freeipa/ticket/6455 --- install/tools/ipa-ca-install | 6 ++++-- install/tools/man/ipa-ca-install.1 | 4 ++-- install/tools/man/ipa-server-install.1 | 4 ++-- ipaserver/install/ca.py | 8 ++++++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 63dbb7d..923ca34 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -77,12 +77,14 @@ def parse_options(): default=None, help=( "The certificate subject base " - "(default O=<realm-name>)")) + "(default O=<realm-name>). " + "RDNs are in LDAP order (most specific RDN first).")) parser.add_option("--ca-subject", dest="ca_subject", default=None, help=( "The CA certificate subject DN " - "(default CN=Certificate Authority,O=<realm-name>)")) + "(default CN=Certificate Authority,O=<realm-name>). " + "RDNs are in LDAP order (most specific RDN first).")) options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1 index 16e5431..76ce115 100644 --- a/install/tools/man/ipa-ca-install.1 +++ b/install/tools/man/ipa-ca-install.1 @@ -47,10 +47,10 @@ Type of the external CA. Possible values are "generic", "ms-cs". Default value i File containing the IPA CA certificate and the external CA certificate chain. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. .TP \fB\-\-ca\-subject\fR=\fISUBJECT\fR -The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME) +The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME). RDNs are in LDAP order (most specific RDN first). .TP \fB\-\-subject\-base\fR=\fISUBJECT\fR -The subject base for certificates issued by IPA (default O=REALM.NAME) +The subject base for certificates issued by IPA (default O=REALM.NAME). RDNs are in LDAP order (most specific RDN first). .TP \fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm. diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 index 9bab143..b2db45b 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -130,10 +130,10 @@ Name of the Kerberos KDC SSL certificate to install File containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC certificates. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. Use this option if the CA certificate is not present in the certificate files. .TP \fB\-\-ca\-subject\fR=\fISUBJECT\fR -The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME) +The CA certificate subject DN (default CN=Certificate Authority,O=REALM.NAME). RDNs are in LDAP order (most specific RDN first). .TP \fB\-\-subject\-base\fR=\fISUBJECT\fR -The subject base for certificates issued by IPA (default O=REALM.NAME) +The subject base for certificates issued by IPA (default O=REALM.NAME). RDNs are in LDAP order (most specific RDN first). .TP \fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm. diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index 8475ed3..be5fbfb 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -434,7 +434,10 @@ def external_cert_files(self, value): subject_base = knob( str, None, - description="The certificate subject base (default O=<realm-name>)", + description=( + "The certificate subject base (default O=<realm-name>). " + "RDNs are in LDAP order (most specific RDN first)." + ), cli_deprecated_names=['--subject'], ) subject_base = master_install_only(subject_base) @@ -447,7 +450,8 @@ def subject_base(self, value): str, None, description=( "The CA certificate subject DN " - "(default CN=Certificate Authority,O=<realm-name>)" + "(default CN=Certificate Authority,O=<realm-name>). " + "RDNs are in LDAP order (most specific RDN first)." ), ) ca_subject = master_install_only(ca_subject) From b18601331cc4826e6d31887a9eebc6336b92f0f9 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 14 Dec 2016 11:33:58 +1000 Subject: [PATCH 10/12] dsinstance: rename 'subject' to 'ca_subject' For consistency with CLI options and other parts of codebase, rename the 'subject' parameters and fields of DsInstance to 'ca_subject'. Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/install/dsinstance.py | 22 +++++++++++----------- ipaserver/install/server/install.py | 4 ++-- ipaserver/install/server/replicainstall.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index cfc2823..a42e707 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -241,7 +241,7 @@ def __init__(self, realm_name=None, domain_name=None, fstore=None, self.dercert = None self.idstart = None self.idmax = None - self.subject = None + self.ca_subject = None self.subject_base = None self.open_ports = [] self.run_init_memberof = True @@ -302,7 +302,7 @@ def __common_post_setup(self): self.step("configuring directory to start on boot", self.__enable) def init_info(self, realm_name, fqdn, domain_name, dm_password, - subject_base, subject, + subject_base, ca_subject, idstart, idmax, pkcs12_info, ca_file=None): self.realm = realm_name.upper() self.serverid = installutils.realm_to_serverid(self.realm) @@ -311,7 +311,7 @@ def init_info(self, realm_name, fqdn, domain_name, dm_password, self.dm_password = dm_password self.domain = domain_name self.subject_base = subject_base - self.subject = subject + self.ca_subject = ca_subject self.idstart = idstart self.idmax = idmax self.pkcs12_info = pkcs12_info @@ -324,11 +324,11 @@ def init_info(self, realm_name, fqdn, domain_name, dm_password, def create_instance(self, realm_name, fqdn, domain_name, dm_password, pkcs12_info=None, idstart=1100, idmax=999999, - subject_base=None, subject=None, + subject_base=None, ca_subject=None, hbac_allow=True, ca_file=None): self.init_info( realm_name, fqdn, domain_name, dm_password, - subject_base, subject, + subject_base, ca_subject, idstart, idmax, pkcs12_info, ca_file=ca_file) self.__common_setup() @@ -364,7 +364,7 @@ def enable_ssl(self): def create_replica(self, realm_name, master_fqdn, fqdn, domain_name, dm_password, - subject_base, subject, + subject_base, ca_subject, api, pkcs12_info=None, ca_file=None, ca_is_configured=None, promote=False): # idstart and idmax are configured so that the range is seen as @@ -380,7 +380,7 @@ def create_replica(self, realm_name, master_fqdn, fqdn, domain_name=domain_name, dm_password=dm_password, subject_base=subject_base, - subject=subject, + ca_subject=ca_subject, idstart=idstart, idmax=idmax, pkcs12_info=pkcs12_info, @@ -789,7 +789,7 @@ def __enable_ssl(self): self.realm, nssdir=dirname, subject_base=self.subject_base, - ca_subject=self.subject, + ca_subject=self.ca_subject, ) if self.pkcs12_info: if self.ca_is_configured: @@ -933,7 +933,7 @@ def __create_indices(self): self._ldap_mod("indices.ldif") def __certmap_conf(self): - write_certmap_conf(self.realm, self.subject) + write_certmap_conf(self.realm, self.ca_subject) sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', @@ -1079,7 +1079,7 @@ def add_ca_cert(self, cacert_fname, cacert_name=''): self.realm, nssdir=dirname, subject_base=self.subject_base, - ca_subject=self.subject, + ca_subject=self.ca_subject, ) if not cacert_name or len(cacert_name) == 0: cacert_name = "Imported CA" @@ -1247,7 +1247,7 @@ def __get_ds_cert(self): self.realm, nssdir=nssdb_dir, subject_base=self.subject_base, - ca_subject=self.subject, + ca_subject=self.ca_subject, ) db.create_from_cacert(paths.IPA_CA_CRT) db.request_service_cert(self.nickname, self.principal, self.fqdn) diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 496ff13..db765d6 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -730,7 +730,7 @@ def install(installer): dm_password, dirsrv_pkcs12_info, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject_base, - subject=options.ca_subject, + ca_subject=options.ca_subject, hbac_allow=not options.no_hbac_allow) else: ds = dsinstance.DsInstance(fstore=fstore, @@ -741,7 +741,7 @@ def install(installer): dm_password, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject_base, - subject=options.ca_subject, + ca_subject=options.ca_subject, hbac_allow=not options.no_hbac_allow) ntpinstance.ntp_ldap_enable(host_name, ds.suffix, realm_name) diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 7f65bac..dad4b74 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -108,7 +108,7 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, domain_name=config.domain_name, dm_password=config.dirman_password, subject_base=config.subject_base, - subject=ca_subject, + ca_subject=ca_subject, pkcs12_info=pkcs12_info, ca_is_configured=ca_is_configured, ca_file=ca_file, From b77c39b4e3b8a1be39b38afe4e7e2b655ef856ce Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Wed, 14 Dec 2016 11:33:58 +1000 Subject: [PATCH 11/12] cainstance: rename 'subject' to 'ca_subject' For consistency with CLI options and other parts of codebase, rename the 'subject' parameters and fields of CAInstance to 'ca_subject'. Part of: https://fedorahosted.org/freeipa/ticket/2614 --- ipaserver/install/ca.py | 2 +- ipaserver/install/cainstance.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index be5fbfb..b3e45cc 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -269,7 +269,7 @@ def install_step_0(standalone, replica_config, options): host_name=host_name) ca.configure_instance(host_name, dm_password, dm_password, subject_base=subject_base, - subject=ca_subject, + ca_subject=ca_subject, ca_signing_algorithm=ca_signing_algorithm, ca_type=ca_type, csr_file=csr_file, diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index 3462618..f933479 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -330,7 +330,7 @@ def configure_instance(self, host_name, dm_password, admin_password, pkcs12_info=None, master_host=None, csr_file=None, cert_file=None, cert_chain_file=None, master_replication_port=None, - subject_base=None, subject=None, + subject_base=None, ca_subject=None, ca_signing_algorithm=None, ca_type=None, ra_p12=None, ra_only=False, promote=False, use_ldaps=False): @@ -356,8 +356,8 @@ def configure_instance(self, host_name, dm_password, admin_password, self.subject_base = \ subject_base or installutils.default_subject_base(self.realm) - self.subject = \ - subject or installutils.default_ca_subject_dn(self.subject_base) + self.ca_subject = \ + ca_subject or installutils.default_ca_subject_dn(self.subject_base) if ca_signing_algorithm is None: self.ca_signing_algorithm = 'SHA256withRSA' @@ -519,7 +519,7 @@ def __spawn_instance(self): str(DN(('cn', 'CA Audit'), self.subject_base))) config.set( "CA", "pki_ca_signing_subject_dn", - str(self.subject)) + str(self.ca_subject)) # Certificate nicknames config.set("CA", "pki_subsystem_nickname", "subsystemCert cert-pki-ca") @@ -705,7 +705,7 @@ def __create_ca_agent(self): userCertificate=[cert_data], description=['2;%s;%s;%s' % ( cert.serial, - DN(self.subject), + DN(self.ca_subject), DN(('CN', 'IPA RA'), self.subject_base))]) conn.add_entry(entry) @@ -758,7 +758,7 @@ def __import_ca_chain(self): # Ok, now we have all the certificates in certs, walk through it # and pull out each certificate and add it to our database - ca_dn = DN(self.subject) + ca_dn = DN(self.ca_subject) for cert in certlist: try: chain_fd, chain_name = tempfile.mkstemp() From 42a309191177a1e6c764880bde25f6021b9cc5dd Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Tue, 20 Dec 2016 20:21:10 +1000 Subject: [PATCH 12/12] Add sanity checks for use of --ca-subject and --subject-base Print an error and terminate if --ca-subject or --subject-base are used when installing a CA-less master or when performing standalone installation of a CA replica. Part of: https://fedorahosted.org/pki/ticket/2614 --- install/tools/ipa-ca-install | 5 +++++ ipaserver/install/server/install.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 923ca34..b143b60 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -119,6 +119,11 @@ def get_dirman_password(): def install_replica(safe_options, options, filename): + if options.ca_subject: + sys.exit("--ca-subject cannot be used when installing a CA replica") + if options.subject_base: + sys.exit("--subject-base cannot be used when installing a CA replica") + if options.promote: if filename is not None: sys.exit("Too many parameters provided. " diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index db765d6..c269827 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -364,6 +364,13 @@ def install_check(installer): setup_ca = True options.setup_ca = setup_ca + if not setup_ca and options.ca_subject: + raise ScriptError( + "--ca-subject cannot be used with CA-less installation") + if not setup_ca and options.subject_base: + raise ScriptError( + "--subject-base cannot be used with CA-less installation") + # first instance of KRA must be installed by ipa-kra-install options.setup_kra = False
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code