When a host is deleted we revoke its certificate, if any.

When a host keytab is disabled we disable all the keytabs and revoke the certificates of its services.

I've also tried to make it more universal to display certificate details when viewing a record with a certificate in it.

rob
>From e1f262397353f37a525a0a3d7d2a8405da1d7db2 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Fri, 5 Nov 2010 15:16:53 -0400
Subject: [PATCH] Revoke a host's certificate (if any) when it is deleted or disabled.

Disable any services when its host is disabled.

This also adds displaying the certificate attributes (subject, etc)
a bit more universal and centralized in a single function.

ticket 297
---
 ipalib/plugins/host.py                   |  207 ++++++++++++++++++++++--------
 ipalib/plugins/service.py                |  130 +++++++++++++------
 tests/test_xmlrpc/test_host_plugin.py    |   24 +++-
 tests/test_xmlrpc/test_service_plugin.py |    7 +
 4 files changed, 272 insertions(+), 96 deletions(-)

diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 884107b..2c23580 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -70,6 +70,8 @@ from ipalib import Str, Flag, Bytes
 from ipalib.plugins.baseldap import *
 from ipalib.plugins.service import split_principal
 from ipalib.plugins.service import validate_certificate
+from ipalib.plugins.service import normalize_certificate
+from ipalib.plugins.service import set_certificate_attrs
 from ipalib.plugins.dns import dns_container_exists, _attribute_types
 from ipalib import _, ngettext
 from ipalib import x509
@@ -96,6 +98,35 @@ def validate_ipaddr(ugettext, ipaddr):
         return _('invalid IP address')
     return None
 
+host_output_params = (
+    Flag('has_keytab',
+        label=_('Keytab'),
+    ),
+    Str('subject',
+        label=_('Subject'),
+    ),
+    Str('serial_number',
+        label=_('Serial Number'),
+    ),
+    Str('issuer',
+        label=_('Issuer'),
+    ),
+    Str('valid_not_before',
+        label=_('Not Before'),
+    ),
+    Str('valid_not_after',
+        label=_('Not After'),
+    ),
+    Str('md5_fingerprint',
+        label=_('Fingerprint (MD5)'),
+    ),
+    Str('sha1_fingerprint',
+        label=_('Fingerprint (SHA1)'),
+    ),
+    Str('revocation_reason?',
+        label=_('Revocation reason'),
+    )
+)
 
 class host(LDAPObject):
     """
@@ -204,6 +235,7 @@ class host_add(LDAPCreate):
     Add a new host.
     """
 
+    has_output_params = LDAPCreate.has_output_params + host_output_params
     msg_summary = _('Added host "%(value)s"')
     takes_options = LDAPCreate.takes_options + (
         Flag('force',
@@ -284,6 +316,7 @@ class host_add(LDAPCreate):
                 # On the off-chance some other extension deletes this from the
                 # context, don't crash.
                 pass
+        set_certificate_attrs(entry_attrs)
         return dn
 
 api.register(host_add)
@@ -372,6 +405,30 @@ class host_del(LDAPDelete):
                                         _attribute_types[attr], record[attr][i])
                             break
 
+        (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate'])
+        if 'usercertificate' in entry_attrs:
+            cert = normalize_certificate(entry_attrs.get('usercertificate')[0])
+            try:
+                serial = unicode(x509.get_serial_number(cert, x509.DER))
+                try:
+                    result = api.Command['cert_show'](unicode(serial))['result']
+                    if 'revocation_reason' not in result:
+                        try:
+                            api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
+                        except errors.NotImplementedError:
+                            # some CA's might not implement revoke
+                            pass
+                except errors.NotImplementedError:
+                    # some CA's might not implement revoke
+                    pass
+            except NSPRError, nsprerr:
+                if nsprerr.errno == -8183:
+                    # If we can't decode the cert them proceed with
+                    # removing the host.
+                    self.log.info("Problem decoding certificate %s" % nsprerr.args[1])
+                else:
+                    raise nsprerr
+
         return dn
 
 api.register(host_del)
@@ -382,6 +439,7 @@ class host_mod(LDAPUpdate):
     Modify information about a host.
     """
 
+    has_output_params = LDAPUpdate.has_output_params + host_output_params
     msg_summary = _('Modified host "%(value)s"')
 
     takes_options = LDAPUpdate.takes_options + (
@@ -409,17 +467,33 @@ class host_mod(LDAPUpdate):
             if 'krbprincipalaux' not in obj_classes:
                 obj_classes.append('krbprincipalaux')
                 entry_attrs['objectclass'] = obj_classes
-        cert = entry_attrs.get('usercertificate')
+        cert = normalize_certificate(entry_attrs.get('usercertificate'))
         if cert:
             (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate'])
             if 'usercertificate' in entry_attrs_old:
-                # FIXME: what to do here? do we revoke the old cert?
-                fmt = 'entry already has a certificate, serial number: %s' % (
-                    x509.get_serial_number(entry_attrs_old['usercertificate'][0], x509.DER)
-                )
-                raise errors.GenericError(format=fmt)
-            # FIXME: decoding should be in normalizer; see service_add
-            entry_attrs['usercertificate'] = base64.b64decode(cert)
+                oldcert = normalize_certificate(entry_attrs_old.get('usercertificate')[0])
+                try:
+                    serial = unicode(x509.get_serial_number(oldcert, x509.DER))
+                    try:
+                        result = api.Command['cert_show'](unicode(serial))['result']
+                        if 'revocation_reason' not in result:
+                            try:
+                                api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
+                            except errors.NotImplementedError:
+                                # some CA's might not implement revoke
+                                pass
+                    except errors.NotImplementedError:
+                        # some CA's might not implement revoke
+                        pass
+                except NSPRError, nsprerr:
+                    if nsprerr.errno == -8183:
+                        # If we can't decode the cert them proceed with
+                        # modifying the host.
+                        self.log.info("Problem decoding certificate %s" % nsprerr.args[1])
+                    else:
+                        raise nsprerr
+
+            entry_attrs['usercertificate'] = cert
         if 'random' in options:
             if options.get('random'):
                 entry_attrs['userpassword'] = ipa_generate_password()
@@ -432,6 +506,7 @@ class host_mod(LDAPUpdate):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         if options.get('random', False):
             entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
+        set_certificate_attrs(entry_attrs)
         return dn
 
 api.register(host_mod)
@@ -442,6 +517,7 @@ class host_find(LDAPSearch):
     Search for hosts.
     """
 
+    has_output_params = LDAPSearch.has_output_params + host_output_params
     msg_summary = ngettext(
         '%(count)d host matched', '%(count)d hosts matched'
     )
@@ -452,6 +528,11 @@ class host_find(LDAPSearch):
             attrs_list.append('l')
         return filter.replace('locality', 'l')
 
+    def post_callback(self, ldap, entries, truncated, *args, **options):
+        for entry in entries:
+            entry_attrs = entry[1]
+            set_certificate_attrs(entry_attrs)
+
 api.register(host_find)
 
 
@@ -459,35 +540,7 @@ class host_show(LDAPRetrieve):
     """
     Display information about a host.
     """
-    has_output_params = (
-        Flag('has_keytab',
-            label=_('Keytab'),
-        ),
-        Str('subject',
-            label=_('Subject'),
-        ),
-        Str('serial_number',
-            label=_('Serial Number'),
-        ),
-        Str('issuer',
-            label=_('Issuer'),
-        ),
-        Str('valid_not_before',
-            label=_('Not Before'),
-        ),
-        Str('valid_not_after',
-            label=_('Not After'),
-        ),
-        Str('md5_fingerprint',
-            label=_('Fingerprint (MD5)'),
-        ),
-        Str('sha1_fingerprint',
-            label=_('Fingerprint (SHA1)'),
-        ),
-        Str('revocation_reason?',
-            label=_('Revocation reason'),
-        )
-    )
+    has_output_params = LDAPRetrieve.has_output_params + host_output_params
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         if 'krblastpwdchange' in entry_attrs:
@@ -497,15 +550,7 @@ class host_show(LDAPRetrieve):
         else:
             entry_attrs['has_keytab'] = False
 
-        if 'usercertificate' in entry_attrs:
-            cert = x509.load_certificate(entry_attrs['usercertificate'][0], datatype=x509.DER)
-            entry_attrs['subject'] = unicode(cert.subject)
-            entry_attrs['serial_number'] = unicode(cert.serial_number)
-            entry_attrs['issuer'] = unicode(cert.issuer)
-            entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str)
-            entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str)
-            entry_attrs['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
-            entry_attrs['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])
+        set_certificate_attrs(entry_attrs)
 
         return dn
 
@@ -517,20 +562,76 @@ class host_disable(LDAPQuery):
     Disable the kerberos key of a host.
     """
     has_output = output.standard_value
-    msg_summary = _('Removed kerberos key from "%(value)s"')
+    msg_summary = _('Removed kerberos key and disabled all services for "%(value)s"')
 
     def execute(self, *keys, **options):
         ldap = self.obj.backend
 
+        # If we aren't given a fqdn, find it
+        if validate_host(None, keys[-1]) is not None:
+            hostentry = api.Command['host_show'](keys[-1])['result']
+            fqdn = hostentry['fqdn'][0]
+        else:
+            fqdn = keys[-1]
+
+        # See if we actually do anthing here, and if not raise an exception
+        done_work = False
+
         dn = self.obj.get_dn(*keys, **options)
-        (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange'])
+        (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange', 'usercertificate'])
+        truncated = True
+        while truncated:
+            try:
+                ret = api.Command['service_find'](fqdn)
+                truncated = ret['truncated']
+                services = ret['result']
+            except errors.NotFound:
+                break
+            else:
+                for entry_attrs in services:
+                    principal = entry_attrs['krbprincipalname'][0]
+                    (service, hostname, realm) = split_principal(principal)
+                    if hostname.lower() == fqdn:
+                        try:
+                            api.Command['service_disable'](principal)
+                            done_work = True
+                        except errors.AlreadyInactive:
+                            pass
 
-        if 'krblastpwdchange' not in entry_attrs:
-            error_msg = _('Host principal has no kerberos key')
-            raise errors.NotFound(reason=error_msg)
+        if 'usercertificate' in entry_attrs:
+            cert = normalize_certificate(entry_attrs.get('usercertificate')[0])
+            try:
+                serial = unicode(x509.get_serial_number(cert, x509.DER))
+                try:
+                    result = api.Command['cert_show'](unicode(serial))['result']
+                    if 'revocation_reason' not in result:
+                        try:
+                            api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
+                        except errors.NotImplementedError:
+                            # some CA's might not implement revoke
+                            pass
+                except errors.NotImplementedError:
+                    # some CA's might not implement revoke
+                    pass
+            except NSPRError, nsprerr:
+                if nsprerr.errno == -8183:
+                    # If we can't decode the cert them proceed with
+                    # disabling the host.
+                    self.log.info("Problem decoding certificate %s" % nsprerr.args[1])
+                else:
+                    raise nsprerr
+
+            # Remove the usercertificate altogether
+            ldap.update_entry(dn, {'usercertificate': None})
+            done_work = True
+
+        if 'krblastpwdchange' in entry_attrs:
+            ldap.remove_principal_key(dn)
+            api.Command['host_mod'](fqdn=keys[-1], setattr=u'enrolledby=')
+            done_work = True
 
-        ldap.remove_principal_key(dn)
-        api.Command['host_mod'](fqdn=keys[-1], setattr=u'enrolledby=')
+        if not done_work:
+            raise errors.AlreadyInactive()
 
         return dict(
             result=True,
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index acaa33d..2ea17be 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -87,6 +87,30 @@ output_params = (
     Str('managedby_host',
         label='Managed by',
     ),
+    Str('subject',
+        label=_('Subject'),
+    ),
+    Str('serial_number',
+        label=_('Serial Number'),
+    ),
+    Str('issuer',
+        label=_('Issuer'),
+    ),
+    Str('valid_not_before',
+        label=_('Not Before'),
+    ),
+    Str('valid_not_after',
+        label=_('Not After'),
+    ),
+    Str('md5_fingerprint',
+        label=_('Fingerprint (MD5)'),
+    ),
+    Str('sha1_fingerprint',
+        label=_('Fingerprint (SHA1)'),
+    ),
+    Str('revocation_reason?',
+        label=_('Revocation reason'),
+    )
 )
 
 def split_principal(principal):
@@ -176,6 +200,30 @@ def normalize_certificate(cert):
 
     return cert
 
+def set_certificate_attrs(entry_attrs):
+    """
+    Set individual attributes from some values from a certificate.
+
+    entry_attrs is a dict of an entry
+
+    returns nothing
+    """
+    if not 'usercertificate' in entry_attrs:
+        return
+    if type(entry_attrs['usercertificate']) in (list, tuple):
+        cert = entry_attrs['usercertificate'][0]
+    else:
+        cert = entry_attrs['usercertificate']
+    cert = normalize_certificate(cert)
+    cert = x509.load_certificate(cert, datatype=x509.DER)
+    entry_attrs['subject'] = unicode(cert.subject)
+    entry_attrs['serial_number'] = unicode(cert.serial_number)
+    entry_attrs['issuer'] = unicode(cert.issuer)
+    entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str)
+    entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str)
+    entry_attrs['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
+    entry_attrs['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])
+
 
 class service(LDAPObject):
     """
@@ -318,6 +366,9 @@ class service_mod(LDAPUpdate):
                 entry_attrs['usercertificate'] = None
         return dn
 
+    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+        set_certificate_attrs(entry_attrs)
+
 api.register(service_mod)
 
 
@@ -353,6 +404,7 @@ class service_find(LDAPSearch):
                     del entry_attrs['krblastpwdchange']
             else:
                 entry_attrs['has_keytab'] = False
+            set_certificate_attrs(entry_attrs)
 
 api.register(service_find)
 
@@ -364,33 +416,6 @@ class service_show(LDAPRetrieve):
     member_attributes = ['managedby']
     takes_options = LDAPRetrieve.takes_options
 
-    has_output_params = LDAPRetrieve.has_output_params + output_params + (
-        Str('subject',
-            label=_('Subject'),
-        ),
-        Str('serial_number',
-            label=_('Serial Number'),
-        ),
-        Str('issuer',
-            label=_('Issuer'),
-        ),
-        Str('valid_not_before',
-            label=_('Not Before'),
-        ),
-        Str('valid_not_after',
-            label=_('Not After'),
-        ),
-        Str('md5_fingerprint',
-            label=_('Fingerprint (MD5)'),
-        ),
-        Str('sha1_fingerprint',
-            label=_('Fingerprint (SHA1)'),
-        ),
-        Str('revocation_reason?',
-            label=_('Revocation reason'),
-        )
-    )
-
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         if 'krblastpwdchange' in entry_attrs:
             entry_attrs['has_keytab'] = True
@@ -399,15 +424,7 @@ class service_show(LDAPRetrieve):
         else:
             entry_attrs['has_keytab'] = False
 
-        if 'usercertificate' in entry_attrs:
-            cert = x509.load_certificate(entry_attrs['usercertificate'][0], datatype=x509.DER)
-            entry_attrs['subject'] = unicode(cert.subject)
-            entry_attrs['serial_number'] = unicode(cert.serial_number)
-            entry_attrs['issuer'] = unicode(cert.issuer)
-            entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str)
-            entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str)
-            entry_attrs['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
-            entry_attrs['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])
+        set_certificate_attrs(entry_attrs)
 
         return dn
 
@@ -445,13 +462,44 @@ class service_disable(LDAPQuery):
         ldap = self.obj.backend
 
         dn = self.obj.get_dn(*keys, **options)
-        (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange'])
+        (dn, entry_attrs) = ldap.get_entry(dn, ['krblastpwdchange', 'usercertificate'])
+
+        # See if we do any work at all here and if not raise an exception
+        done_work = False
 
-        if 'krblastpwdchange' not in entry_attrs:
-            error_msg = _('Service principal has no kerberos key')
-            raise errors.NotFound(reason=error_msg)
+        if 'usercertificate' in entry_attrs:
+            cert = normalize_certificate(entry_attrs.get('usercertificate')[0])
+            try:
+                serial = unicode(x509.get_serial_number(cert, x509.DER))
+                try:
+                    result = api.Command['cert_show'](unicode(serial))['result']
+                    if 'revocation_reason' not in result:
+                        try:
+                            api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
+                        except errors.NotImplementedError:
+                            # some CA's might not implement revoke
+                            pass
+                except errors.NotImplementedError:
+                    # some CA's might not implement revoke
+                    pass
+            except NSPRError, nsprerr:
+                if nsprerr.errno == -8183:
+                    # If we can't decode the cert them proceed with
+                    # disabling the service
+                    self.log.info("Problem decoding certificate %s" % nsprerr.args[1])
+                else:
+                    raise nsprerr
+
+            # Remove the usercertificate altogether
+            ldap.update_entry(dn, {'usercertificate': None})
+            done_work = True
+
+        if 'krblastpwdchange' in entry_attrs:
+            ldap.remove_principal_key(dn)
+            done_work = True
 
-        ldap.remove_principal_key(dn)
+        if not done_work:
+            raise errors.AlreadyInactive()
 
         return dict(
             result=True,
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index 631a5de..283674c 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -25,6 +25,7 @@ Test the `ipalib.plugins.host` module.
 from ipalib import api, errors
 from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
 from tests.test_xmlrpc import objectclasses
+import base64
 
 
 fqdn1 = u'testhost1.%s' % api.env.domain
@@ -35,6 +36,8 @@ service1dn = u'krbprincipalname=%s,cn=services,cn=accounts,%s' % (service1.lower
 fqdn2 = u'shouldnotexist.%s' % api.env.domain
 dn2 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn)
 
+servercert = 'MIICbzCCAdigAwIBAgICA/4wDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgwOTE1MDIyN1oXDTIwMDgwOTE1MDIyN1owKTEMMAoGA1UEChMDSVBBMRkwFwYDVQQDExBwdW1hLmdyZXlvYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwYbfEOQPgGenPn9vt1JFKvWm/Je3y2tawGWA3LXDuqfFJyYtZ8ib3TcBUOnLk9WK5g2qCwHaNlei7bj8ggIfr5hegAVe10cun+wYErjnYo7hsHYd+57VZezeipWrXu+7NoNd4+c4A5lk4A/xJay9j3bYx2oOM8BEox4xWYoWge1ljPrc5JK46f0X7AGW4F2VhnKPnf8rwSuzI1U8VGjutyM9TWNy3m9KMWeScjyG/ggIpOjUDMV7HkJL0Di61lznR9jXubpiEC7gWGbTp84eGl/Nn9bgK1AwHfJ2lHwfoY4uiL7ge1gyP6EvuUlHoBzdb7pekiX28iePjW3iEG9IawIDAQABoyIwIDARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4GBACRESLemRV9BPxfEgbALuxH5oE8jQm8WZ3pm2pALbpDlAd9wQc3yVf6RtkfVthyDnM18bg7IhxKpd77/p3H8eCnS8w5MLVRda6ktUC6tGhFTS4QKAf0WyDGTcIgkXbeDw0OPAoNHivoXbIXIIRxlw/XgaSaMzJQDBG8iROsN4kCv'
+
 
 class test_host(Declarative):
 
@@ -201,7 +204,8 @@ class test_host(Declarative):
 
         dict(
             desc='Update %r' % fqdn1,
-            command=('host_mod', [fqdn1], dict(description=u'Updated host 1')),
+            command=('host_mod', [fqdn1], dict(description=u'Updated host 1',
+                usercertificate=servercert)),
             expected=dict(
                 value=fqdn1,
                 summary=u'Modified host "%s"' % fqdn1,
@@ -210,6 +214,14 @@ class test_host(Declarative):
                     fqdn=[fqdn1],
                     l=[u'Undisclosed location 1'],
                     krbprincipalname=[u'host/%...@%s' % (fqdn1, api.env.realm)],
+                    usercertificate=[base64.b64decode(servercert)],
+                    valid_not_before=u'Mon Aug 09 15:02:27 2010 UTC',
+                    valid_not_after=u'Sun Aug 09 15:02:27 2020 UTC',
+                    subject=u'CN=puma.greyoak.com,O=IPA',
+                    serial_number=u'1022',
+                    md5_fingerprint=u'ef:63:31:e4:33:54:8d:fd:fe:c8:66:57:09:03:5f:09',
+                    sha1_fingerprint=u'e3:33:2c:d9:7c:e9:77:74:2a:ac:3b:b8:76:b0:86:29:98:43:58:11',
+                    issuer=u'CN=IPA Test Certificate Authority',
                 ),
             ),
         ),
@@ -227,7 +239,15 @@ class test_host(Declarative):
                     description=[u'Updated host 1'],
                     l=[u'Undisclosed location 1'],
                     krbprincipalname=[u'host/%...@%s' % (fqdn1, api.env.realm)],
-                    has_keytab=False
+                    has_keytab=False,
+                    usercertificate=[base64.b64decode(servercert)],
+                    valid_not_before=u'Mon Aug 09 15:02:27 2010 UTC',
+                    valid_not_after=u'Sun Aug 09 15:02:27 2020 UTC',
+                    subject=u'CN=puma.greyoak.com,O=IPA',
+                    serial_number=u'1022',
+                    md5_fingerprint=u'ef:63:31:e4:33:54:8d:fd:fe:c8:66:57:09:03:5f:09',
+                    sha1_fingerprint=u'e3:33:2c:d9:7c:e9:77:74:2a:ac:3b:b8:76:b0:86:29:98:43:58:11',
+                    issuer=u'CN=IPA Test Certificate Authority',
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py
index 1427169..fc8e08e 100644
--- a/tests/test_xmlrpc/test_service_plugin.py
+++ b/tests/test_xmlrpc/test_service_plugin.py
@@ -234,6 +234,13 @@ class test_host(Declarative):
                     usercertificate=[base64.b64decode(servercert)],
                     krbprincipalname=[service1],
                     managedby_host=[fqdn1],
+                    valid_not_before=u'Mon Aug 09 15:02:27 2010 UTC',
+                    valid_not_after=u'Sun Aug 09 15:02:27 2020 UTC',
+                    subject=u'CN=puma.greyoak.com,O=IPA',
+                    serial_number=u'1022',
+                    md5_fingerprint=u'ef:63:31:e4:33:54:8d:fd:fe:c8:66:57:09:03:5f:09',
+                    sha1_fingerprint=u'e3:33:2c:d9:7c:e9:77:74:2a:ac:3b:b8:76:b0:86:29:98:43:58:11',
+                    issuer=u'CN=IPA Test Certificate Authority',
                 ),
             ),
         ),
-- 
1.7.2.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to