544061
From d0d29ccc324bb9f95bffbe3162ee5c3c61c6086a Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Thu, 11 Jul 2019 15:17:04 +1000
544061
Subject: [PATCH] move MSCSTemplate classes to ipalib
544061
544061
As we expand the integration tests for external CA functionality, it
544061
is helpful (and avoids duplication) to use the MSCSTemplate*
544061
classes.  These currently live in ipaserver.install.cainstance, but
544061
ipatests is no longer permitted to import from ipaserver (see commit
544061
81714976e5e13131654c78eb734746a20237c933).  So move these classes to
544061
ipalib.
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 install/tools/ipa-ca-install.in               |   6 +-
544061
 ipalib/x509.py                                | 171 +++++++++++++++++
544061
 ipaserver/install/ca.py                       |  11 +-
544061
 ipaserver/install/cainstance.py               | 180 +-----------------
544061
 ipaserver/install/ipa_cacert_manage.py        |  14 +-
544061
 ipatests/test_integration/test_external_ca.py |  11 +-
544061
 ipatests/test_ipalib/test_x509.py             | 115 +++++++++++
544061
 .../test_install/test_cainstance.py           | 123 ------------
544061
 8 files changed, 307 insertions(+), 324 deletions(-)
544061
 delete mode 100644 ipatests/test_ipaserver/test_install/test_cainstance.py
544061
544061
diff --git a/install/tools/ipa-ca-install.in b/install/tools/ipa-ca-install.in
544061
index 0700c0c38b..ce6d5fcb52 100644
544061
--- a/install/tools/ipa-ca-install.in
544061
+++ b/install/tools/ipa-ca-install.in
544061
@@ -37,7 +37,7 @@ from ipaserver.install import cainstance, service
544061
 from ipaserver.install import custodiainstance
544061
 from ipaserver.masters import find_providing_server
544061
 from ipapython import version
544061
-from ipalib import api
544061
+from ipalib import api, x509
544061
 from ipalib.constants import DOMAIN_LEVEL_1
544061
 from ipapython.config import IPAOptionParser
544061
 from ipapython.ipa_log_manager import standard_logging_setup
544061
@@ -68,13 +68,13 @@ def parse_options():
544061
                       default=False, help="unattended installation never prompts the user")
544061
     parser.add_option("--external-ca", dest="external_ca", action="store_true",
544061
                       default=False, help="Generate a CSR to be signed by an external CA")
544061
-    ext_cas = tuple(x.value for x in cainstance.ExternalCAType)
544061
+    ext_cas = tuple(x.value for x in x509.ExternalCAType)
544061
     parser.add_option("--external-ca-type", dest="external_ca_type",
544061
                       type="choice", choices=ext_cas,
544061
                       metavar="{{{0}}}".format(",".join(ext_cas)),
544061
                       help="Type of the external CA. Default: generic")
544061
     parser.add_option("--external-ca-profile", dest="external_ca_profile",
544061
-                      type='constructor', constructor=cainstance.ExternalCAProfile,
544061
+                      type='constructor', constructor=x509.ExternalCAProfile,
544061
                       default=None, metavar="PROFILE-SPEC",
544061
                       help="Specify the certificate profile/template to use "
544061
                            "at the external CA")
544061
diff --git a/ipalib/x509.py b/ipalib/x509.py
544061
index ab3c5f553d..1f612a3797 100644
544061
--- a/ipalib/x509.py
544061
+++ b/ipalib/x509.py
544061
@@ -34,6 +34,7 @@
544061
 import os
544061
 import binascii
544061
 import datetime
544061
+import enum
544061
 import ipaddress
544061
 import ssl
544061
 import base64
544061
@@ -47,6 +48,7 @@
544061
     Encoding, PublicFormat, PrivateFormat, load_pem_private_key
544061
 )
544061
 import pyasn1
544061
+import pyasn1.error
544061
 from pyasn1.type import univ, char, namedtype, tag
544061
 from pyasn1.codec.der import decoder, encoder
544061
 from pyasn1_modules import rfc2315, rfc2459
544061
@@ -745,3 +747,172 @@ def format_datetime(t):
544061
     if t.tzinfo is None:
544061
         t = t.replace(tzinfo=UTC())
544061
     return unicode(t.strftime("%a %b %d %H:%M:%S %Y %Z"))
544061
+
544061
+
544061
+class ExternalCAType(enum.Enum):
544061
+    GENERIC = 'generic'
544061
+    MS_CS = 'ms-cs'
544061
+
544061
+
544061
+class ExternalCAProfile:
544061
+    """
544061
+    An external CA profile configuration.  Currently the only
544061
+    subclasses are for Microsoft CAs, for providing data in the
544061
+    "Certificate Template" extension.
544061
+
544061
+    Constructing this class will actually return an instance of a
544061
+    subclass.
544061
+
544061
+    Subclasses MUST set ``valid_for``.
544061
+
544061
+    """
544061
+    def __init__(self, s=None):
544061
+        self.unparsed_input = s
544061
+
544061
+    # Which external CA types is the data valid for?
544061
+    # A set of VALUES of the ExternalCAType enum.
544061
+    valid_for = set()
544061
+
544061
+    def __new__(cls, s=None):
544061
+        """Construct the ExternalCAProfile value.
544061
+
544061
+        Return an instance of a subclass determined by
544061
+        the format of the argument.
544061
+
544061
+        """
544061
+        # we are directly constructing a subclass; instantiate
544061
+        # it and be done
544061
+        if cls is not ExternalCAProfile:
544061
+            return super(ExternalCAProfile, cls).__new__(cls)
544061
+
544061
+        # construction via the base class; therefore the string
544061
+        # argument is required, and is used to determine which
544061
+        # subclass to construct
544061
+        if s is None:
544061
+            raise ValueError('string argument is required')
544061
+
544061
+        parts = s.split(':')
544061
+
544061
+        try:
544061
+            # Is the first part on OID?
544061
+            _oid = univ.ObjectIdentifier(parts[0])
544061
+
544061
+            # It is; construct a V2 template
544061
+            # pylint: disable=too-many-function-args
544061
+            return MSCSTemplateV2.__new__(MSCSTemplateV2, s)
544061
+
544061
+        except pyasn1.error.PyAsn1Error:
544061
+            # It is not an OID; treat as a template name
544061
+            # pylint: disable=too-many-function-args
544061
+            return MSCSTemplateV1.__new__(MSCSTemplateV1, s)
544061
+
544061
+    def __getstate__(self):
544061
+        return self.unparsed_input
544061
+
544061
+    def __setstate__(self, state):
544061
+        # explicitly call __init__ method to initialise object
544061
+        self.__init__(state)
544061
+
544061
+
544061
+class MSCSTemplate(ExternalCAProfile):
544061
+    """
544061
+    An Microsoft AD-CS Template specifier.
544061
+
544061
+    Subclasses MUST set ext_oid.
544061
+
544061
+    Subclass constructors MUST set asn1obj.
544061
+
544061
+    """
544061
+    valid_for = set([ExternalCAType.MS_CS.value])
544061
+
544061
+    ext_oid = None  # extension OID, as a Python str
544061
+    asn1obj = None  # unencoded extension data
544061
+
544061
+    def get_ext_data(self):
544061
+        """Return DER-encoded extension data."""
544061
+        return encoder.encode(self.asn1obj)
544061
+
544061
+
544061
+class MSCSTemplateV1(MSCSTemplate):
544061
+    """
544061
+    A v1 template specifier, per
544061
+    https://msdn.microsoft.com/en-us/library/cc250011.aspx.
544061
+
544061
+    ::
544061
+
544061
+        CertificateTemplateName ::= SEQUENCE {
544061
+           Name            UTF8String
544061
+        }
544061
+
544061
+    But note that a bare BMPString is used in practice.
544061
+
544061
+    """
544061
+    ext_oid = "1.3.6.1.4.1.311.20.2"
544061
+
544061
+    def __init__(self, s):
544061
+        super(MSCSTemplateV1, self).__init__(s)
544061
+        parts = s.split(':')
544061
+        if len(parts) > 1:
544061
+            raise ValueError(
544061
+                "Cannot specify certificate template version when using name.")
544061
+        self.asn1obj = char.BMPString(str(parts[0]))
544061
+
544061
+
544061
+class MSCSTemplateV2(MSCSTemplate):
544061
+    """
544061
+    A v2 template specifier, per
544061
+    https://msdn.microsoft.com/en-us/library/windows/desktop/aa378274(v=vs.85).aspx
544061
+
544061
+    ::
544061
+
544061
+        CertificateTemplate ::= SEQUENCE {
544061
+            templateID              EncodedObjectID,
544061
+            templateMajorVersion    TemplateVersion,
544061
+            templateMinorVersion    TemplateVersion OPTIONAL
544061
+        }
544061
+
544061
+        TemplateVersion ::= INTEGER (0..4294967295)
544061
+
544061
+    """
544061
+    ext_oid = "1.3.6.1.4.1.311.21.7"
544061
+
544061
+    @staticmethod
544061
+    def check_version_in_range(desc, n):
544061
+        if n < 0 or n >= 2**32:
544061
+            raise ValueError(
544061
+                "Template {} version must be in range 0..4294967295"
544061
+                .format(desc))
544061
+
544061
+    def __init__(self, s):
544061
+        super(MSCSTemplateV2, self).__init__(s)
544061
+
544061
+        parts = s.split(':')
544061
+
544061
+        obj = CertificateTemplateV2()
544061
+        if len(parts) < 2 or len(parts) > 3:
544061
+            raise ValueError(
544061
+                "Incorrect template specification; required format is: "
544061
+                "<oid>:<majorVersion>[:<minorVersion>]")
544061
+        try:
544061
+            obj['templateID'] = univ.ObjectIdentifier(parts[0])
544061
+
544061
+            major = int(parts[1])
544061
+            self.check_version_in_range("major", major)
544061
+            obj['templateMajorVersion'] = major
544061
+
544061
+            if len(parts) > 2:
544061
+                minor = int(parts[2])
544061
+                self.check_version_in_range("minor", minor)
544061
+                obj['templateMinorVersion'] = int(parts[2])
544061
+
544061
+        except pyasn1.error.PyAsn1Error:
544061
+            raise ValueError("Could not parse certificate template specifier.")
544061
+        self.asn1obj = obj
544061
+
544061
+
544061
+class CertificateTemplateV2(univ.Sequence):
544061
+    componentType = namedtype.NamedTypes(
544061
+        namedtype.NamedType('templateID', univ.ObjectIdentifier()),
544061
+        namedtype.NamedType('templateMajorVersion', univ.Integer()),
544061
+        namedtype.OptionalNamedType('templateMinorVersion', univ.Integer())
544061
+    )
544061
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
544061
index 6b040b311a..8fb5e3ec91 100644
544061
--- a/ipaserver/install/ca.py
544061
+++ b/ipaserver/install/ca.py
544061
@@ -28,7 +28,7 @@
544061
 from ipaplatform.paths import paths
544061
 from ipaserver.install import installutils, certs
544061
 from ipaserver.install.replication import replica_conn_check
544061
-from ipalib import api, errors
544061
+from ipalib import api, errors, x509
544061
 from ipapython.dn import DN
544061
 
544061
 from . import conncheck, dogtag, cainstance
544061
@@ -216,8 +216,7 @@ def install_check(standalone, replica_config, options):
544061
                 paths.ROOT_IPA_CSR)
544061
 
544061
         if not options.external_ca_type:
544061
-            options.external_ca_type = \
544061
-                cainstance.ExternalCAType.GENERIC.value
544061
+            options.external_ca_type = x509.ExternalCAType.GENERIC.value
544061
 
544061
         if options.external_ca_profile is not None:
544061
             # check that profile is valid for the external ca type
544061
@@ -478,13 +477,11 @@ class CAInstallInterface(dogtag.DogtagInstallInterface,
544061
     external_ca = master_install_only(external_ca)
544061
 
544061
     external_ca_type = knob(
544061
-        cainstance.ExternalCAType, None,
544061
-        description="Type of the external CA",
544061
-    )
544061
+        x509.ExternalCAType, None, description="Type of the external CA")
544061
     external_ca_type = master_install_only(external_ca_type)
544061
 
544061
     external_ca_profile = knob(
544061
-        type=cainstance.ExternalCAProfile,
544061
+        type=x509.ExternalCAProfile,
544061
         default=None,
544061
         description=(
544061
             "Specify the certificate profile/template to use at the "
544061
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
544061
index 6e1fc724db..2295581870 100644
544061
--- a/ipaserver/install/cainstance.py
544061
+++ b/ipaserver/install/cainstance.py
544061
@@ -26,7 +26,6 @@
544061
 import logging
544061
 
544061
 import dbus
544061
-import enum
544061
 import ldap
544061
 import os
544061
 import pwd
544061
@@ -39,10 +38,6 @@
544061
 import tempfile
544061
 from configparser import RawConfigParser
544061
 
544061
-from pyasn1.codec.der import encoder
544061
-from pyasn1.type import char, univ, namedtype
544061
-import pyasn1.error
544061
-
544061
 from ipalib import api
544061
 from ipalib import x509
544061
 from ipalib import errors
544061
@@ -80,11 +75,6 @@
544061
 ]
544061
 
544061
 
544061
-class ExternalCAType(enum.Enum):
544061
-    GENERIC = 'generic'
544061
-    MS_CS = 'ms-cs'
544061
-
544061
-
544061
 def check_ports():
544061
     """Check that dogtag ports (8080, 8443) are available.
544061
 
544061
@@ -367,7 +357,7 @@ def configure_instance(self, host_name, dm_password, admin_password,
544061
         if ca_type is not None:
544061
             self.ca_type = ca_type
544061
         else:
544061
-            self.ca_type = ExternalCAType.GENERIC.value
544061
+            self.ca_type = x509.ExternalCAType.GENERIC.value
544061
         self.external_ca_profile = external_ca_profile
544061
 
544061
         self.no_db_setup = promote
544061
@@ -537,12 +527,12 @@ def __spawn_instance(self):
544061
                 pki_ca_signing_csr_path=self.csr_file,
544061
             )
544061
 
544061
-            if self.ca_type == ExternalCAType.MS_CS.value:
544061
+            if self.ca_type == x509.ExternalCAType.MS_CS.value:
544061
                 # Include MS template name extension in the CSR
544061
                 template = self.external_ca_profile
544061
                 if template is None:
544061
                     # default template name
544061
-                    template = MSCSTemplateV1(u"SubCA")
544061
+                    template = x509.MSCSTemplateV1(u"SubCA")
544061
 
544061
                 ext_data = binascii.hexlify(template.get_ext_data())
544061
                 cfg.update(
544061
@@ -2081,170 +2071,6 @@ def update_ipa_conf():
544061
         parser.write(f)
544061
 
544061
 
544061
-class ExternalCAProfile:
544061
-    """
544061
-    An external CA profile configuration.  Currently the only
544061
-    subclasses are for Microsoft CAs, for providing data in the
544061
-    "Certificate Template" extension.
544061
-
544061
-    Constructing this class will actually return an instance of a
544061
-    subclass.
544061
-
544061
-    Subclasses MUST set ``valid_for``.
544061
-
544061
-    """
544061
-    def __init__(self, s=None):
544061
-        self.unparsed_input = s
544061
-
544061
-    # Which external CA types is the data valid for?
544061
-    # A set of VALUES of the ExternalCAType enum.
544061
-    valid_for = set()
544061
-
544061
-    def __new__(cls, s=None):
544061
-        """Construct the ExternalCAProfile value.
544061
-
544061
-        Return an instance of a subclass determined by
544061
-        the format of the argument.
544061
-
544061
-        """
544061
-        # we are directly constructing a subclass; instantiate
544061
-        # it and be done
544061
-        if cls is not ExternalCAProfile:
544061
-            return super(ExternalCAProfile, cls).__new__(cls)
544061
-
544061
-        # construction via the base class; therefore the string
544061
-        # argument is required, and is used to determine which
544061
-        # subclass to construct
544061
-        if s is None:
544061
-            raise ValueError('string argument is required')
544061
-
544061
-        parts = s.split(':')
544061
-
544061
-        try:
544061
-            # Is the first part on OID?
544061
-            _oid = univ.ObjectIdentifier(parts[0])
544061
-
544061
-            # It is; construct a V2 template
544061
-            # pylint: disable=too-many-function-args
544061
-            return MSCSTemplateV2.__new__(MSCSTemplateV2, s)
544061
-
544061
-        except pyasn1.error.PyAsn1Error:
544061
-            # It is not an OID; treat as a template name
544061
-            # pylint: disable=too-many-function-args
544061
-            return MSCSTemplateV1.__new__(MSCSTemplateV1, s)
544061
-
544061
-    def __getstate__(self):
544061
-        return self.unparsed_input
544061
-
544061
-    def __setstate__(self, state):
544061
-        # explicitly call __init__ method to initialise object
544061
-        self.__init__(state)
544061
-
544061
-
544061
-class MSCSTemplate(ExternalCAProfile):
544061
-    """
544061
-    An Microsoft AD-CS Template specifier.
544061
-
544061
-    Subclasses MUST set ext_oid.
544061
-
544061
-    Subclass constructors MUST set asn1obj.
544061
-
544061
-    """
544061
-    valid_for = set([ExternalCAType.MS_CS.value])
544061
-
544061
-    ext_oid = None  # extension OID, as a Python str
544061
-    asn1obj = None  # unencoded extension data
544061
-
544061
-    def get_ext_data(self):
544061
-        """Return DER-encoded extension data."""
544061
-        return encoder.encode(self.asn1obj)
544061
-
544061
-
544061
-class MSCSTemplateV1(MSCSTemplate):
544061
-    """
544061
-    A v1 template specifier, per
544061
-    https://msdn.microsoft.com/en-us/library/cc250011.aspx.
544061
-
544061
-    ::
544061
-
544061
-        CertificateTemplateName ::= SEQUENCE {
544061
-           Name            UTF8String
544061
-        }
544061
-
544061
-    But note that a bare BMPString is used in practice.
544061
-
544061
-    """
544061
-    ext_oid = "1.3.6.1.4.1.311.20.2"
544061
-
544061
-    def __init__(self, s):
544061
-        super(MSCSTemplateV1, self).__init__(s)
544061
-        parts = s.split(':')
544061
-        if len(parts) > 1:
544061
-            raise ValueError(
544061
-                "Cannot specify certificate template version when using name.")
544061
-        self.asn1obj = char.BMPString(str(parts[0]))
544061
-
544061
-
544061
-class MSCSTemplateV2(MSCSTemplate):
544061
-    """
544061
-    A v2 template specifier, per
544061
-    https://msdn.microsoft.com/en-us/library/windows/desktop/aa378274(v=vs.85).aspx
544061
-
544061
-    ::
544061
-
544061
-        CertificateTemplate ::= SEQUENCE {
544061
-            templateID              EncodedObjectID,
544061
-            templateMajorVersion    TemplateVersion,
544061
-            templateMinorVersion    TemplateVersion OPTIONAL
544061
-        }
544061
-
544061
-        TemplateVersion ::= INTEGER (0..4294967295)
544061
-
544061
-    """
544061
-    ext_oid = "1.3.6.1.4.1.311.21.7"
544061
-
544061
-    @staticmethod
544061
-    def check_version_in_range(desc, n):
544061
-        if n < 0 or n >= 2**32:
544061
-            raise ValueError(
544061
-                "Template {} version must be in range 0..4294967295"
544061
-                .format(desc))
544061
-
544061
-    def __init__(self, s):
544061
-        super(MSCSTemplateV2, self).__init__(s)
544061
-
544061
-        parts = s.split(':')
544061
-
544061
-        obj = CertificateTemplateV2()
544061
-        if len(parts) < 2 or len(parts) > 3:
544061
-            raise ValueError(
544061
-                "Incorrect template specification; required format is: "
544061
-                "<oid>:<majorVersion>[:<minorVersion>]")
544061
-        try:
544061
-            obj['templateID'] = univ.ObjectIdentifier(parts[0])
544061
-
544061
-            major = int(parts[1])
544061
-            self.check_version_in_range("major", major)
544061
-            obj['templateMajorVersion'] = major
544061
-
544061
-            if len(parts) > 2:
544061
-                minor = int(parts[2])
544061
-                self.check_version_in_range("minor", minor)
544061
-                obj['templateMinorVersion'] = int(parts[2])
544061
-
544061
-        except pyasn1.error.PyAsn1Error:
544061
-            raise ValueError("Could not parse certificate template specifier.")
544061
-        self.asn1obj = obj
544061
-
544061
-
544061
-class CertificateTemplateV2(univ.Sequence):
544061
-    componentType = namedtype.NamedTypes(
544061
-        namedtype.NamedType('templateID', univ.ObjectIdentifier()),
544061
-        namedtype.NamedType('templateMajorVersion', univ.Integer()),
544061
-        namedtype.OptionalNamedType('templateMinorVersion', univ.Integer())
544061
-    )
544061
-
544061
-
544061
 if __name__ == "__main__":
544061
     standard_logging_setup("install.log")
544061
     ds = dsinstance.DsInstance()
544061
diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py
544061
index 3f113c35bf..37dcc2befa 100644
544061
--- a/ipaserver/install/ipa_cacert_manage.py
544061
+++ b/ipaserver/install/ipa_cacert_manage.py
544061
@@ -65,7 +65,7 @@ def add_options(cls, parser):
544061
             "--external-ca", dest='self_signed',
544061
             action='store_false',
544061
             help="Sign the renewed certificate by external CA")
544061
-        ext_cas = tuple(x.value for x in cainstance.ExternalCAType)
544061
+        ext_cas = tuple(x.value for x in x509.ExternalCAType)
544061
         renew_group.add_option(
544061
             "--external-ca-type", dest="external_ca_type",
544061
             type="choice", choices=ext_cas,
544061
@@ -73,7 +73,7 @@ def add_options(cls, parser):
544061
             help="Type of the external CA. Default: generic")
544061
         renew_group.add_option(
544061
             "--external-ca-profile", dest="external_ca_profile",
544061
-            type='constructor', constructor=cainstance.ExternalCAProfile,
544061
+            type='constructor', constructor=x509.ExternalCAProfile,
544061
             default=None, metavar="PROFILE-SPEC",
544061
             help="Specify the certificate profile/template to use "
544061
                  "at the external CA")
544061
@@ -224,11 +224,11 @@ def renew_external_step_1(self, ca):
544061
         options = self.options
544061
 
544061
         if not options.external_ca_type:
544061
-            options.external_ca_type = cainstance.ExternalCAType.GENERIC.value
544061
+            options.external_ca_type = x509.ExternalCAType.GENERIC.value
544061
 
544061
-        if options.external_ca_type == cainstance.ExternalCAType.MS_CS.value \
544061
+        if options.external_ca_type == x509.ExternalCAType.MS_CS.value \
544061
                 and options.external_ca_profile is None:
544061
-            options.external_ca_profile = cainstance.MSCSTemplateV1(u"SubCA")
544061
+            options.external_ca_profile = x509.MSCSTemplateV1(u"SubCA")
544061
 
544061
         if options.external_ca_profile is not None:
544061
             # check that profile is valid for the external ca type
544061
@@ -352,11 +352,11 @@ def resubmit_request(self, ca=RENEWAL_CA_NAME, profile=None):
544061
         timeout = api.env.startup_timeout + 60
544061
 
544061
         cm_profile = None
544061
-        if isinstance(profile, cainstance.MSCSTemplateV1):
544061
+        if isinstance(profile, x509.MSCSTemplateV1):
544061
             cm_profile = profile.unparsed_input
544061
 
544061
         cm_template = None
544061
-        if isinstance(profile, cainstance.MSCSTemplateV2):
544061
+        if isinstance(profile, x509.MSCSTemplateV2):
544061
             cm_template = profile.unparsed_input
544061
 
544061
         logger.debug("resubmitting certmonger request '%s'", self.request_id)
544061
diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py
544061
index a42355217d..5aa2b7bba0 100644
544061
--- a/ipatests/test_integration/test_external_ca.py
544061
+++ b/ipatests/test_integration/test_external_ca.py
544061
@@ -108,14 +108,14 @@ def check_ipaca_issuerDN(host, expected_dn):
544061
     assert "Issuer DN: {}".format(expected_dn) in result.stdout_text
544061
 
544061
 
544061
-def check_mscs_extension(ipa_csr, oid, value):
544061
+def check_mscs_extension(ipa_csr, template):
544061
     csr = x509.load_pem_x509_csr(ipa_csr, default_backend())
544061
     extensions = [
544061
         ext for ext in csr.extensions
544061
-        if ext.oid.dotted_string == oid
544061
+        if ext.oid.dotted_string == template.ext_oid
544061
     ]
544061
     assert extensions
544061
-    assert extensions[0].value.value == value
544061
+    assert extensions[0].value.value == template.get_ext_data()
544061
 
544061
 
544061
 class TestExternalCA(IntegrationTest):
544061
@@ -134,10 +134,7 @@ def test_external_ca(self):
544061
 
544061
         # check CSR for extension
544061
         ipa_csr = self.master.get_file_contents(paths.ROOT_IPA_CSR)
544061
-        # Values for MSCSTemplateV1('SubCA')
544061
-        oid = "1.3.6.1.4.1.311.20.2"
544061
-        value = b'\x1e\n\x00S\x00u\x00b\x00C\x00A'
544061
-        check_mscs_extension(ipa_csr, oid, value)
544061
+        check_mscs_extension(ipa_csr, ipa_x509.MSCSTemplateV1(u'SubCA'))
544061
 
544061
         # Sign CA, transport it to the host and get ipa a root ca paths.
544061
         root_ca_fname, ipa_ca_fname = tasks.sign_ca_and_transport(
544061
diff --git a/ipatests/test_ipalib/test_x509.py b/ipatests/test_ipalib/test_x509.py
544061
index ff7e6de2f7..284b998316 100644
544061
--- a/ipatests/test_ipalib/test_x509.py
544061
+++ b/ipatests/test_ipalib/test_x509.py
544061
@@ -22,7 +22,11 @@
544061
 """
544061
 
544061
 import base64
544061
+from binascii import hexlify
544061
+from configparser import RawConfigParser
544061
 import datetime
544061
+from io import StringIO
544061
+import pickle
544061
 
544061
 import pytest
544061
 
544061
@@ -268,3 +272,114 @@ def test_ipa_demo_letsencrypt(self):
544061
             b'0 \x06\x03U\x1d%\x01\x01\xff\x04\x160\x14\x06\x08+\x06\x01'
544061
             b'\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x02'
544061
         )
544061
+
544061
+
544061
+class test_ExternalCAProfile:
544061
+    def test_MSCSTemplateV1_good(self):
544061
+        o = x509.MSCSTemplateV1("MySubCA")
544061
+        assert hexlify(o.get_ext_data()) == b'1e0e004d007900530075006200430041'
544061
+
544061
+    def test_MSCSTemplateV1_bad(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV1("MySubCA:1")
544061
+
544061
+    def test_MSCSTemplateV1_pickle_roundtrip(self):
544061
+        o = x509.MSCSTemplateV1("MySubCA")
544061
+        s = pickle.dumps(o)
544061
+        assert o.get_ext_data() == pickle.loads(s).get_ext_data()
544061
+
544061
+    def test_MSCSTemplateV2_too_few_parts(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4")
544061
+
544061
+    def test_MSCSTemplateV2_too_many_parts(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:100:200:300")
544061
+
544061
+    def test_MSCSTemplateV2_bad_oid(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("not_an_oid:1")
544061
+
544061
+    def test_MSCSTemplateV2_non_numeric_major_version(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:major:200")
544061
+
544061
+    def test_MSCSTemplateV2_non_numeric_minor_version(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:100:minor")
544061
+
544061
+    def test_MSCSTemplateV2_major_version_lt_zero(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:-1:200")
544061
+
544061
+    def test_MSCSTemplateV2_minor_version_lt_zero(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:100:-1")
544061
+
544061
+    def test_MSCSTemplateV2_major_version_gt_max(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:4294967296:200")
544061
+
544061
+    def test_MSCSTemplateV2_minor_version_gt_max(self):
544061
+        with pytest.raises(ValueError):
544061
+            x509.MSCSTemplateV2("1.2.3.4:100:4294967296")
544061
+
544061
+    def test_MSCSTemplateV2_good_major(self):
544061
+        o = x509.MSCSTemplateV2("1.2.3.4:4294967295")
544061
+        assert hexlify(o.get_ext_data()) == b'300c06032a0304020500ffffffff'
544061
+
544061
+    def test_MSCSTemplateV2_good_major_minor(self):
544061
+        o = x509.MSCSTemplateV2("1.2.3.4:4294967295:0")
544061
+        assert hexlify(o.get_ext_data()) \
544061
+            == b'300f06032a0304020500ffffffff020100'
544061
+
544061
+    def test_MSCSTemplateV2_pickle_roundtrip(self):
544061
+        o = x509.MSCSTemplateV2("1.2.3.4:4294967295:0")
544061
+        s = pickle.dumps(o)
544061
+        assert o.get_ext_data() == pickle.loads(s).get_ext_data()
544061
+
544061
+    def test_ExternalCAProfile_dispatch(self):
544061
+        """
544061
+        Test that constructing ExternalCAProfile actually returns an
544061
+        instance of the appropriate subclass.
544061
+        """
544061
+        assert isinstance(
544061
+            x509.ExternalCAProfile("MySubCA"),
544061
+            x509.MSCSTemplateV1)
544061
+        assert isinstance(
544061
+            x509.ExternalCAProfile("1.2.3.4:100"),
544061
+            x509.MSCSTemplateV2)
544061
+
544061
+    def test_write_pkispawn_config_file_MSCSTemplateV1(self):
544061
+        template = x509.MSCSTemplateV1(u"SubCA")
544061
+        expected = (
544061
+            '[CA]\n'
544061
+            'pki_req_ext_oid = 1.3.6.1.4.1.311.20.2\n'
544061
+            'pki_req_ext_data = 1e0a00530075006200430041\n\n'
544061
+        )
544061
+        self._test_write_pkispawn_config_file(template, expected)
544061
+
544061
+    def test_write_pkispawn_config_file_MSCSTemplateV2(self):
544061
+        template = x509.MSCSTemplateV2(u"1.2.3.4:4294967295")
544061
+        expected = (
544061
+            '[CA]\n'
544061
+            'pki_req_ext_oid = 1.3.6.1.4.1.311.21.7\n'
544061
+            'pki_req_ext_data = 300c06032a0304020500ffffffff\n\n'
544061
+        )
544061
+        self._test_write_pkispawn_config_file(template, expected)
544061
+
544061
+    def _test_write_pkispawn_config_file(self, template, expected):
544061
+        """
544061
+        Test that the values we read from an ExternalCAProfile
544061
+        object can be used to produce a reasonable-looking pkispawn
544061
+        configuration.
544061
+        """
544061
+        config = RawConfigParser()
544061
+        config.optionxform = str
544061
+        config.add_section("CA")
544061
+        config.set("CA", "pki_req_ext_oid", template.ext_oid)
544061
+        config.set("CA", "pki_req_ext_data",
544061
+                   hexlify(template.get_ext_data()).decode('ascii'))
544061
+        out = StringIO()
544061
+        config.write(out)
544061
+        assert out.getvalue() == expected
544061
diff --git a/ipatests/test_ipaserver/test_install/test_cainstance.py b/ipatests/test_ipaserver/test_install/test_cainstance.py
544061
deleted file mode 100644
544061
index 02d9758e4a..0000000000
544061
--- a/ipatests/test_ipaserver/test_install/test_cainstance.py
544061
+++ /dev/null
544061
@@ -1,123 +0,0 @@
544061
-#
544061
-# Copyright (C) 2017  FreeIPA Contributors see COPYING for license
544061
-#
544061
-
544061
-from binascii import hexlify
544061
-from io import StringIO
544061
-import pickle
544061
-from configparser import RawConfigParser
544061
-import pytest
544061
-from ipaserver.install import cainstance
544061
-
544061
-pytestmark = pytest.mark.tier0
544061
-
544061
-
544061
-class test_ExternalCAProfile:
544061
-    def test_MSCSTemplateV1_good(self):
544061
-        o = cainstance.MSCSTemplateV1("MySubCA")
544061
-        assert hexlify(o.get_ext_data()) == b'1e0e004d007900530075006200430041'
544061
-
544061
-    def test_MSCSTemplateV1_bad(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV1("MySubCA:1")
544061
-
544061
-    def test_MSCSTemplateV1_pickle_roundtrip(self):
544061
-        o = cainstance.MSCSTemplateV1("MySubCA")
544061
-        s = pickle.dumps(o)
544061
-        assert o.get_ext_data() == pickle.loads(s).get_ext_data()
544061
-
544061
-    def test_MSCSTemplateV2_too_few_parts(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4")
544061
-
544061
-    def test_MSCSTemplateV2_too_many_parts(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:100:200:300")
544061
-
544061
-    def test_MSCSTemplateV2_bad_oid(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("not_an_oid:1")
544061
-
544061
-    def test_MSCSTemplateV2_non_numeric_major_version(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:major:200")
544061
-
544061
-    def test_MSCSTemplateV2_non_numeric_minor_version(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:100:minor")
544061
-
544061
-    def test_MSCSTemplateV2_major_version_lt_zero(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:-1:200")
544061
-
544061
-    def test_MSCSTemplateV2_minor_version_lt_zero(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:100:-1")
544061
-
544061
-    def test_MSCSTemplateV2_major_version_gt_max(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:4294967296:200")
544061
-
544061
-    def test_MSCSTemplateV2_minor_version_gt_max(self):
544061
-        with pytest.raises(ValueError):
544061
-            cainstance.MSCSTemplateV2("1.2.3.4:100:4294967296")
544061
-
544061
-    def test_MSCSTemplateV2_good_major(self):
544061
-        o = cainstance.MSCSTemplateV2("1.2.3.4:4294967295")
544061
-        assert hexlify(o.get_ext_data()) == b'300c06032a0304020500ffffffff'
544061
-
544061
-    def test_MSCSTemplateV2_good_major_minor(self):
544061
-        o = cainstance.MSCSTemplateV2("1.2.3.4:4294967295:0")
544061
-        assert hexlify(o.get_ext_data()) \
544061
-            == b'300f06032a0304020500ffffffff020100'
544061
-
544061
-    def test_MSCSTemplateV2_pickle_roundtrip(self):
544061
-        o = cainstance.MSCSTemplateV2("1.2.3.4:4294967295:0")
544061
-        s = pickle.dumps(o)
544061
-        assert o.get_ext_data() == pickle.loads(s).get_ext_data()
544061
-
544061
-    def test_ExternalCAProfile_dispatch(self):
544061
-        """
544061
-        Test that constructing ExternalCAProfile actually returns an
544061
-        instance of the appropriate subclass.
544061
-        """
544061
-        assert isinstance(
544061
-            cainstance.ExternalCAProfile("MySubCA"),
544061
-            cainstance.MSCSTemplateV1)
544061
-        assert isinstance(
544061
-            cainstance.ExternalCAProfile("1.2.3.4:100"),
544061
-            cainstance.MSCSTemplateV2)
544061
-
544061
-    def test_write_pkispawn_config_file_MSCSTemplateV1(self):
544061
-        template = cainstance.MSCSTemplateV1(u"SubCA")
544061
-        expected = (
544061
-            '[CA]\n'
544061
-            'pki_req_ext_oid = 1.3.6.1.4.1.311.20.2\n'
544061
-            'pki_req_ext_data = 1e0a00530075006200430041\n\n'
544061
-        )
544061
-        self._test_write_pkispawn_config_file(template, expected)
544061
-
544061
-    def test_write_pkispawn_config_file_MSCSTemplateV2(self):
544061
-        template = cainstance.MSCSTemplateV2(u"1.2.3.4:4294967295")
544061
-        expected = (
544061
-            '[CA]\n'
544061
-            'pki_req_ext_oid = 1.3.6.1.4.1.311.21.7\n'
544061
-            'pki_req_ext_data = 300c06032a0304020500ffffffff\n\n'
544061
-        )
544061
-        self._test_write_pkispawn_config_file(template, expected)
544061
-
544061
-    def _test_write_pkispawn_config_file(self, template, expected):
544061
-        """
544061
-        Test that the values we read from an ExternalCAProfile
544061
-        object can be used to produce a reasonable-looking pkispawn
544061
-        configuration.
544061
-        """
544061
-        config = RawConfigParser()
544061
-        config.optionxform = str
544061
-        config.add_section("CA")
544061
-        config.set("CA", "pki_req_ext_oid", template.ext_oid)
544061
-        config.set("CA", "pki_req_ext_data",
544061
-                   hexlify(template.get_ext_data()).decode('ascii'))
544061
-        out = StringIO()
544061
-        config.write(out)
544061
-        assert out.getvalue() == expected
544061
From e632b220798833bcd65c6b266610c800ed0914d7 Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Fri, 12 Jul 2019 13:13:02 +1000
544061
Subject: [PATCH] install: fix --external-ca-profile option
544061
544061
Commit dd47cfc75a69618f486abefb70f2649ebf8264e7 removed the ability
544061
to set pki_req_ext_oid and pki_req_ext_data in the pkispawn config.
544061
This results in the --external-ca-profile option never setting the
544061
requested values in the CSR (the default V1 template type specifying
544061
"SubCA" is always used).
544061
544061
Remove relevant fields from both ipaca_default.ini and
544061
ipaca_customize.ini.  This allows the IPA framework to set the
544061
values (i.e. when --external-ca-type=ms-cs and
544061
--external-ca-profile=... demand it).  It also allows users to
544061
override the pki_req_ext_* settings.
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
Related: https://pagure.io/freeipa/issue/5608
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 install/share/ipaca_customize.ini | 5 -----
544061
 install/share/ipaca_default.ini   | 1 -
544061
 2 files changed, 6 deletions(-)
544061
544061
diff --git a/install/share/ipaca_customize.ini b/install/share/ipaca_customize.ini
544061
index 130ec2c102..6d58579af8 100644
544061
--- a/install/share/ipaca_customize.ini
544061
+++ b/install/share/ipaca_customize.ini
544061
@@ -93,11 +93,6 @@ pki_ca_signing_key_type=%(ipa_ca_key_type)s
544061
 pki_ca_signing_signing_algorithm=%(ipa_ca_signing_algorithm)s
544061
 pki_ca_signing_token=%(pki_token_name)s
544061
 
544061
-# MS subca request ext data
544061
-pki_req_ext_oid=1.3.6.1.4.1.311.20.2
544061
-pki_req_ext_critical=False
544061
-pki_req_ext_data=1E0A00530075006200430041
544061
-
544061
 ## ocspSigningCert cert-pki-ca
544061
 pki_ocsp_signing_key_algorithm=%(ipa_key_algorithm)s
544061
 pki_ocsp_signing_key_size=%(ipa_key_size)s
544061
diff --git a/install/share/ipaca_default.ini b/install/share/ipaca_default.ini
544061
index fedc1b9a74..2b9900286e 100644
544061
--- a/install/share/ipaca_default.ini
544061
+++ b/install/share/ipaca_default.ini
544061
@@ -115,7 +115,6 @@ pki_ca_starting_crl_number=0
544061
 
544061
 pki_external=False
544061
 pki_external_step_two=False
544061
-pki_req_ext_add=False
544061
 
544061
 pki_external_pkcs12_path=%(pki_pkcs12_path)s
544061
 pki_external_pkcs12_password=%(pki_pkcs12_password)s
544061
From 71af731b3069fa1b2c0b51a3b917b5bc4da54350 Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Fri, 12 Jul 2019 13:24:51 +1000
544061
Subject: [PATCH] Fix use of incorrect variable
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
Related: https://pagure.io/freeipa/issue/5608
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 ipaserver/install/dogtaginstance.py | 2 +-
544061
 1 file changed, 1 insertion(+), 1 deletion(-)
544061
544061
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
544061
index cc75d89746..5dca721d6c 100644
544061
--- a/ipaserver/install/dogtaginstance.py
544061
+++ b/ipaserver/install/dogtaginstance.py
544061
@@ -853,7 +853,7 @@ def _verify_immutable(self, config, immutable_settings, filename):
544061
         if errs:
544061
             raise ValueError(
544061
                 '{} overrides immutable options:\n{}'.format(
544061
-                    filename, '\n'.join(errors)
544061
+                    filename, '\n'.join(errs)
544061
                 )
544061
             )
544061
 
544061
From 83ed05725110de19a7098678274ecaaaf6a2c9c9 Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <frase@frase.id.au>
544061
Date: Wed, 20 Feb 2019 18:34:33 +1100
544061
Subject: [PATCH] Add more tests for --external-ca-profile handling
544061
544061
Add tests for remaining untested scenarios of --external-ca-profile
544061
handling in ipa-server-install.
544061
544061
ipa-ca-install and ipa-cacert-manage remain untested at present.
544061
544061
Fixes: https://pagure.io/freeipa/issue/7548
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 ipatests/test_integration/test_external_ca.py | 97 ++++++++++++++++++-
544061
 1 file changed, 95 insertions(+), 2 deletions(-)
544061
544061
diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py
544061
index 5aa2b7bba0..dc9a09b43b 100644
544061
--- a/ipatests/test_integration/test_external_ca.py
544061
+++ b/ipatests/test_integration/test_external_ca.py
544061
@@ -74,10 +74,10 @@ def match_in_journal(host, string, since='today', services=('certmonger',)):
544061
     return match
544061
 
544061
 
544061
-def install_server_external_ca_step1(host, extra_args=()):
544061
+def install_server_external_ca_step1(host, extra_args=(), raiseonerr=True):
544061
     """Step 1 to install the ipa server with external ca"""
544061
     return tasks.install_master(
544061
-        host, external_ca=True, extra_args=extra_args
544061
+        host, external_ca=True, extra_args=extra_args, raiseonerr=raiseonerr,
544061
     )
544061
 
544061
 
544061
@@ -478,3 +478,96 @@ def test_master_install_ca2(self):
544061
             'certutil', '-L', '-d', paths.PKI_TOMCAT_ALIAS_DIR,
544061
             '-n', cert_nick])
544061
         assert "CN=RootCA2" in result.stdout_text
544061
+
544061
+
544061
+def _step1_profile(master, s):
544061
+    return install_server_external_ca_step1(
544061
+        master,
544061
+        extra_args=['--external-ca-type=ms-cs', f'--external-ca-profile={s}'],
544061
+        raiseonerr=False,
544061
+    )
544061
+
544061
+
544061
+def _test_invalid_profile(master, profile):
544061
+    result = _step1_profile(master, profile)
544061
+    assert result.returncode != 0
544061
+    assert '--external-ca-profile' in result.stderr_text
544061
+
544061
+
544061
+def _test_valid_profile(master, profile_cls, profile):
544061
+    result = _step1_profile(master, profile)
544061
+    assert result.returncode == 0
544061
+    ipa_csr = master.get_file_contents(paths.ROOT_IPA_CSR)
544061
+    check_mscs_extension(ipa_csr, profile_cls(profile))
544061
+
544061
+
544061
+class TestExternalCAProfileV1(IntegrationTest):
544061
+    """
544061
+    Test that --external-ca-profile=Foo gets propagated to the CSR.
544061
+
544061
+    The default template extension when --external-ca-type=ms-cs,
544061
+    a V1 extension with value "SubCA", already gets tested by the
544061
+    ``TestExternalCA`` class.
544061
+
544061
+    We only need to do Step 1 of installation, then check the CSR.
544061
+
544061
+    """
544061
+    def test_invalid_v1_template(self):
544061
+        _test_invalid_profile(self.master, 'NotAnOid:1')
544061
+
544061
+    def test_valid_v1_template(self):
544061
+        _test_valid_profile(
544061
+            self.master, ipa_x509.MSCSTemplateV1, 'TemplateOfAwesome')
544061
+
544061
+
544061
+class TestExternalCAProfileV2MajorOnly(IntegrationTest):
544061
+    """
544061
+    Test that V2 template specifiers without minor version get
544061
+    propagated to CSR.  This class also tests all error modes in
544061
+    specifying a V2 template, those being:
544061
+
544061
+    - no major version specified
544061
+    - too many parts specified (i.e. major, minor, and then some more)
544061
+    - major version is not an int
544061
+    - major version is negative
544061
+    - minor version is not an int
544061
+    - minor version is negative
544061
+
544061
+    We only need to do Step 1 of installation, then check the CSR.
544061
+
544061
+    """
544061
+    def test_v2_template_too_few_parts(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4')
544061
+
544061
+    def test_v2_template_too_many_parts(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4:100:200:300')
544061
+
544061
+    def test_v2_template_major_version_not_int(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4:wat:200')
544061
+
544061
+    def test_v2_template_major_version_negative(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4:-1:200')
544061
+
544061
+    def test_v2_template_minor_version_not_int(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4:100:wat')
544061
+
544061
+    def test_v2_template_minor_version_negative(self):
544061
+        _test_invalid_profile(self.master, '1.2.3.4:100:-2')
544061
+
544061
+    def test_v2_template_valid_major_only(self):
544061
+        _test_valid_profile(
544061
+            self.master, ipa_x509.MSCSTemplateV2, '1.2.3.4:100')
544061
+
544061
+
544061
+class TestExternalCAProfileV2MajorMinor(IntegrationTest):
544061
+    """
544061
+    Test that V2 template specifiers _with_ minor version get
544061
+    propagated to CSR.  All error modes of V2 template specifiers
544061
+    were tested in ``TestExternalCAProfileV2Major``.
544061
+
544061
+    We only need to do Step 1 of installation, then check the CSR.
544061
+
544061
+    """
544061
+    def test_v2_template_valid_major_minor(self):
544061
+        _test_valid_profile(
544061
+            self.master, ipa_x509.MSCSTemplateV2, '1.2.3.4:100:200')
544061
From a627df87c31e4d8399bd9fab43c0c4772ddd8955 Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Thu, 11 Jul 2019 20:22:33 +1000
544061
Subject: [PATCH] Collapse --external-ca-profile tests into single class
544061
544061
To avoid having to spawn new CI hosts for each kind of
544061
--external-ca-profile argument we are testing, collapse the three
544061
separate test classes into one.  Uninstall the half-installed IPA
544061
after each section of tests.
544061
544061
This change is in response to review comment
544061
https://github.com/freeipa/freeipa/pull/2852#pullrequestreview-220442170.
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 ipatests/test_integration/test_external_ca.py | 34 ++++++++++++++-----
544061
 1 file changed, 26 insertions(+), 8 deletions(-)
544061
544061
diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py
544061
index dc9a09b43b..714aebd4a8 100644
544061
--- a/ipatests/test_integration/test_external_ca.py
544061
+++ b/ipatests/test_integration/test_external_ca.py
544061
@@ -501,8 +501,18 @@ def _test_valid_profile(master, profile_cls, profile):
544061
     check_mscs_extension(ipa_csr, profile_cls(profile))
544061
 
544061
 
544061
-class TestExternalCAProfileV1(IntegrationTest):
544061
+class TestExternalCAProfileScenarios(IntegrationTest):
544061
     """
544061
+    Test the various --external-ca-profile scenarios.
544061
+    This test is broken into sections, with each section first
544061
+    testing invalid arguments, then a valid argument, and finally
544061
+    uninstalling the half-installed IPA.
544061
+
544061
+    """
544061
+
544061
+    '''
544061
+    Tranche 1: version 1 templates.
544061
+
544061
     Test that --external-ca-profile=Foo gets propagated to the CSR.
544061
 
544061
     The default template extension when --external-ca-type=ms-cs,
544061
@@ -511,7 +521,7 @@ class TestExternalCAProfileV1(IntegrationTest):
544061
 
544061
     We only need to do Step 1 of installation, then check the CSR.
544061
 
544061
-    """
544061
+    '''
544061
     def test_invalid_v1_template(self):
544061
         _test_invalid_profile(self.master, 'NotAnOid:1')
544061
 
544061
@@ -519,9 +529,12 @@ def test_valid_v1_template(self):
544061
         _test_valid_profile(
544061
             self.master, ipa_x509.MSCSTemplateV1, 'TemplateOfAwesome')
544061
 
544061
+    def test_uninstall_1(self):
544061
+        tasks.uninstall_master(self.master)
544061
+
544061
+    '''
544061
+    Tranche 2: V2 templates without minor version.
544061
 
544061
-class TestExternalCAProfileV2MajorOnly(IntegrationTest):
544061
-    """
544061
     Test that V2 template specifiers without minor version get
544061
     propagated to CSR.  This class also tests all error modes in
544061
     specifying a V2 template, those being:
544061
@@ -535,7 +548,7 @@ class TestExternalCAProfileV2MajorOnly(IntegrationTest):
544061
 
544061
     We only need to do Step 1 of installation, then check the CSR.
544061
 
544061
-    """
544061
+    '''
544061
     def test_v2_template_too_few_parts(self):
544061
         _test_invalid_profile(self.master, '1.2.3.4')
544061
 
544061
@@ -558,16 +571,21 @@ def test_v2_template_valid_major_only(self):
544061
         _test_valid_profile(
544061
             self.master, ipa_x509.MSCSTemplateV2, '1.2.3.4:100')
544061
 
544061
+    def test_uninstall_2(self):
544061
+        tasks.uninstall_master(self.master)
544061
+
544061
+    '''
544061
+    Tranche 3: V2 templates with minor version.
544061
 
544061
-class TestExternalCAProfileV2MajorMinor(IntegrationTest):
544061
-    """
544061
     Test that V2 template specifiers _with_ minor version get
544061
     propagated to CSR.  All error modes of V2 template specifiers
544061
     were tested in ``TestExternalCAProfileV2Major``.
544061
 
544061
     We only need to do Step 1 of installation, then check the CSR.
544061
 
544061
-    """
544061
+    '''
544061
     def test_v2_template_valid_major_minor(self):
544061
         _test_valid_profile(
544061
             self.master, ipa_x509.MSCSTemplateV2, '1.2.3.4:100:200')
544061
+
544061
+    # this is the end; no need to uninstall.
544061
From 740964c3c47fd2cd216c233d8d9df1840eaa01ee Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Thu, 11 Jul 2019 20:27:02 +1000
544061
Subject: [PATCH] ci: add --external-ca-profile tests to nightly
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 ipatests/prci_definitions/nightly_f28.yaml        | 12 ++++++++++++
544061
 ipatests/prci_definitions/nightly_f29.yaml        | 12 ++++++++++++
544061
 ipatests/prci_definitions/nightly_master.yaml     | 12 ++++++++++++
544061
 ipatests/prci_definitions/nightly_master_pki.yaml | 12 ++++++++++++
544061
 ipatests/prci_definitions/nightly_rawhide.yaml    | 12 ++++++++++++
544061
 5 files changed, 60 insertions(+)
544061
544061
diff --git a/ipatests/prci_definitions/nightly_f28.yaml b/ipatests/prci_definitions/nightly_f28.yaml
544061
index fe86730444..d1605e6b5c 100644
544061
--- a/ipatests/prci_definitions/nightly_f28.yaml
544061
+++ b/ipatests/prci_definitions/nightly_f28.yaml
544061
@@ -75,6 +75,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-28/external_ca_templates:
544061
+    requires: [fedora-28/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-28/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *ci-master-f28
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-28/test_topologies:
544061
     requires: [fedora-28/build]
544061
     priority: 50
544061
diff --git a/ipatests/prci_definitions/nightly_f29.yaml b/ipatests/prci_definitions/nightly_f29.yaml
544061
index 57c1b624fe..ed88eb15c8 100644
544061
--- a/ipatests/prci_definitions/nightly_f29.yaml
544061
+++ b/ipatests/prci_definitions/nightly_f29.yaml
544061
@@ -75,6 +75,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-29/external_ca_templates:
544061
+    requires: [fedora-29/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-29/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *ci-master-f29
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-29/test_topologies:
544061
     requires: [fedora-29/build]
544061
     priority: 50
544061
diff --git a/ipatests/prci_definitions/nightly_master.yaml b/ipatests/prci_definitions/nightly_master.yaml
544061
index dc63f37426..0a66a13490 100644
544061
--- a/ipatests/prci_definitions/nightly_master.yaml
544061
+++ b/ipatests/prci_definitions/nightly_master.yaml
544061
@@ -75,6 +75,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-30/external_ca_templates:
544061
+    requires: [fedora-30/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-30/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *ci-master-f30
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-30/test_topologies:
544061
     requires: [fedora-30/build]
544061
     priority: 50
544061
diff --git a/ipatests/prci_definitions/nightly_master_pki.yaml b/ipatests/prci_definitions/nightly_master_pki.yaml
544061
index 1bb0af0244..ed2e38d3ed 100644
544061
--- a/ipatests/prci_definitions/nightly_master_pki.yaml
544061
+++ b/ipatests/prci_definitions/nightly_master_pki.yaml
544061
@@ -75,6 +75,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-29/external_ca_templates:
544061
+    requires: [fedora-29/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-29/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *pki-master-f29
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-29/test_vault:
544061
     requires: [fedora-29/build]
544061
     priority: 50
544061
diff --git a/ipatests/prci_definitions/nightly_rawhide.yaml b/ipatests/prci_definitions/nightly_rawhide.yaml
544061
index 301878467c..14433fcc0a 100644
544061
--- a/ipatests/prci_definitions/nightly_rawhide.yaml
544061
+++ b/ipatests/prci_definitions/nightly_rawhide.yaml
544061
@@ -75,6 +75,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-rawhide/external_ca_templates:
544061
+    requires: [fedora-rawhide/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-rawhide/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *ci-master-frawhide
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-rawhide/test_topologies:
544061
     requires: [fedora-rawhide/build]
544061
     priority: 50
544061
From 011c5283cec28ea4361eff5d2ee98da9cd3db41a Mon Sep 17 00:00:00 2001
544061
From: Fraser Tweedale <ftweedal@redhat.com>
544061
Date: Thu, 11 Jul 2019 20:27:02 +1000
544061
Subject: [PATCH] ci: add --external-ca-profile tests to gating
544061
544061
Part of: https://pagure.io/freeipa/issue/7548
544061
544061
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
544061
---
544061
 ipatests/prci_definitions/gating.yaml | 12 ++++++++++++
544061
 1 file changed, 12 insertions(+)
544061
544061
diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml
544061
index 4d0107d956..81fa4bba10 100644
544061
--- a/ipatests/prci_definitions/gating.yaml
544061
+++ b/ipatests/prci_definitions/gating.yaml
544061
@@ -87,6 +87,18 @@ jobs:
544061
         timeout: 3600
544061
         topology: *master_1repl
544061
 
544061
+  fedora-30/external_ca_templates:
544061
+    requires: [fedora-30/build]
544061
+    priority: 50
544061
+    job:
544061
+      class: RunPytest
544061
+      args:
544061
+        build_url: '{fedora-30/build_url}'
544061
+        test_suite: test_integration/test_external_ca.py::TestExternalCAProfileScenarios
544061
+        template: *ci-master-f30
544061
+        timeout: 3600
544061
+        topology: *master_1repl
544061
+
544061
   fedora-30/test_topologies:
544061
     requires: [fedora-30/build]
544061
     priority: 50