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