diff options
author | Rob Crittenden <rcritten@redhat.com> | 2012-11-15 10:55:33 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2013-02-19 11:52:33 -0500 |
commit | 462beacc9d13968128fa320d155016df2d72a20a (patch) | |
tree | 2c53b8cd152e56d51368fe561b48cb0da06b12fa | |
parent | 74c11d88aeb43fe45a22e787c60f8c20c454ec56 (diff) | |
download | freeipa-462beacc9d13968128fa320d155016df2d72a20a.tar.gz freeipa-462beacc9d13968128fa320d155016df2d72a20a.tar.xz freeipa-462beacc9d13968128fa320d155016df2d72a20a.zip |
Implement the cert-find command for the dogtag CA backend.
Use a new RESTful API provided by dogtag 10+. Construct an XML document
representing the search request. The output is limited to whatever dogtag
sends us, there is no way to request additional attributes other than
to read each certificate individually.
dogtag uses a boolean for each search term to indicate that it is used.
Presense of the search item is not enough, both need to be set.
The search operation is unauthenticated
Design page: http://freeipa.org/page/V3/Cert_find
https://fedorahosted.org/freeipa/ticket/2528
-rw-r--r-- | API.txt | 23 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | ipalib/plugins/cert.py | 137 | ||||
-rw-r--r-- | ipaserver/plugins/dogtag.py | 138 | ||||
-rw-r--r-- | ipaserver/plugins/rabase.py | 8 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_cert.py | 312 |
6 files changed, 598 insertions, 22 deletions
@@ -425,6 +425,29 @@ args: 1,0,2 arg: Any('methods*') output: Output('count', <type 'int'>, None) output: Output('results', (<type 'list'>, <type 'tuple'>), None) +command: cert_find +args: 0,17,4 +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') +option: Flag('exactly?', autofill=True, default=False) +option: Str('issuedon_from?', autofill=False) +option: Str('issuedon_to?', autofill=False) +option: Int('max_serial_number?', autofill=False, maxvalue=2147483647) +option: Int('min_serial_number?', autofill=False, minvalue=0) +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +option: Int('revocation_reason?', autofill=False, maxvalue=10, minvalue=0) +option: Str('revokedon_from?', autofill=False) +option: Str('revokedon_to?', autofill=False) +option: Int('sizelimit?', default=100, minvalue=0) +option: Str('subject?', autofill=False) +option: Str('validnotafter_from?', autofill=False) +option: Str('validnotafter_to?', autofill=False) +option: Str('validnotbefore_from?', autofill=False) +option: Str('validnotbefore_to?', autofill=False) +option: Str('version?', exclude='webui') +output: Output('count', <type 'int'>, None) +output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None)) +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: Output('truncated', <type 'bool'>, None) command: cert_remove_hold args: 1,0,1 arg: Str('serial_number') @@ -89,4 +89,4 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=50 +IPA_API_VERSION_MINOR=51 diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py index 3aa01621d..51493c34e 100644 --- a/ipalib/plugins/cert.py +++ b/ipalib/plugins/cert.py @@ -24,18 +24,20 @@ if api.env.enable_ra is not True: # In this case, abort loading this plugin module... raise SkipPluginModule(reason='env.enable_ra is not True') import os +import time from ipalib import Command, Str, Int, Bytes, Flag, File from ipalib import errors from ipalib import pkcs10 from ipalib import x509 from ipalib import util +from ipalib import ngettext from ipalib.plugins.virtual import * from ipalib.plugins.service import split_principal import base64 import traceback from ipalib.text import _ from ipalib.request import context -from ipalib.output import Output +from ipalib import output from ipalib.plugins.service import validate_principal import nss.nss as nss from nss.error import NSPRError @@ -60,6 +62,18 @@ In order to request a certificate: * The host must exist * The service must exist (or you use the --add option to automatically add it) +SEARCHING: + +Certificates may be searched on by certificate subject, serial number, +revocation reason, validity dates and the issued date. + +When searching on dates the _from date does a >= search and the _to date +does a <= search. When combined these are done as an AND. + +Dates are treated as GMT to match the dates in the certificates. + +The date format is YYYY-mm-dd. + EXAMPLES: Request a new certificate and add the principal: @@ -77,6 +91,15 @@ EXAMPLES: Check the status of a signing request: ipa cert-status 10 + Search for certificates by hostname: + ipa cert-find --subject=ipaserver.example.com + + Search for revoked certificates by reason: + ipa cert-find --revocation-reason=5 + + Search for certificates based on issuance date + ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07 + IPA currently immediately issues (or declines) all certificate requests so the status of a request is not normally useful. This is for future use or the case where a CA does not immediately issue a certificate. @@ -100,6 +123,17 @@ http://www.ietf.org/rfc/rfc5280.txt """) +def validate_pkidate(ugettext, value): + """ + A date in the format of %Y-%m-%d + """ + try: + ts = time.strptime(value, '%Y-%m-%d') + except ValueError, e: + return str(e) + + return None + def get_csr_hostname(csr): """ Return the value of CN in the subject of the request or None @@ -262,7 +296,7 @@ class cert_request(VirtualCommand): ) has_output = ( - Output('result', + output.Output('result', type=dict, doc=_('Dictionary mapping variable name to value'), ), @@ -593,3 +627,102 @@ class cert_remove_hold(VirtualCommand): ) api.register(cert_remove_hold) + + +class cert_find(Command): + __doc__ = _('Search for existing certificates.') + + takes_options = ( + Str('subject?', + label=_('Subject'), + doc=_('Subject'), + autofill=False, + ), + Int('revocation_reason?', + label=_('Reason'), + doc=_('Reason for revoking the certificate (0-10)'), + minvalue=0, + maxvalue=10, + autofill=False, + ), + Int('min_serial_number?', + doc=_("minimum serial number"), + autofill=False, + minvalue=0, + ), + Int('max_serial_number?', + doc=_("maximum serial number"), + autofill=False, + maxvalue=2147483647, + ), + Flag('exactly?', + doc=_('match the common name exactly'), + autofill=False, + ), + Str('validnotafter_from?', validate_pkidate, + doc=_('Valid not after from this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('validnotafter_to?', validate_pkidate, + doc=_('Valid not after to this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('validnotbefore_from?', validate_pkidate, + doc=_('Valid not before from this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('validnotbefore_to?', validate_pkidate, + doc=_('Valid not before to this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('issuedon_from?', validate_pkidate, + doc=_('Issued on from this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('issuedon_to?', validate_pkidate, + doc=_('Issued on to this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('revokedon_from?', validate_pkidate, + doc=_('Revoked on from this date (YYYY-mm-dd)'), + autofill=False, + ), + Str('revokedon_to?', validate_pkidate, + doc=_('Revoked on to this date (YYYY-mm-dd)'), + autofill=False, + ), + Int('sizelimit?', + label=_('Size Limit'), + doc=_('Maximum number of certs returned'), + flags=['no_display'], + minvalue=0, + default=100, + ), + ) + + has_output = output.standard_list_of_entries + has_output_params = ( + Str('serial_number_hex', + label=_('Serial number (hex)'), + ), + Str('serial_number', + label=_('Serial number'), + ), + Str('status', + label=_('Status'), + ), + ) + + msg_summary = ngettext( + '%(count)d certificate matched', '%(count)d certificates matched', 0 + ) + + def execute(self, **options): + ret = dict( + result=self.Backend.ra.find(options) + ) + ret['count'] = len(ret['result']) + ret['truncated'] = False + return ret + +api.register(cert_find) diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py index d52bb7e98..28bf754cb 100644 --- a/ipaserver/plugins/dogtag.py +++ b/ipaserver/plugins/dogtag.py @@ -237,9 +237,14 @@ digits and nothing else follows. ''' from lxml import etree +import urllib +import urllib2 import datetime +import time from ipapython.dn import DN from ldap.filter import escape_filter_chars +import ipapython.dogtag +from ipapython import ipautil # These are general status return values used when # CMSServlet.outputError() is invoked. @@ -1715,4 +1720,137 @@ class ra(rabase.rabase): return cmd_result + def find(self, options): + """ + Search for certificates + + :param options: dictionary of search options + """ + + def convert_time(value): + """ + Convert time to milliseconds to pass to dogtag + """ + ts = time.strptime(value, '%Y-%m-%d') + return int(time.mktime(ts) * 1000) + + self.debug('%s.find()', self.fullname) + + # Create the root element + page = etree.Element('CertSearchRequest') + + # Make a new document tree + doc = etree.ElementTree(page) + + # This matches the default configuration of the pki tool. + booloptions = {'serialNumberRangeInUse': True, + 'subjectInUse': False, + 'matchExactly': False, + 'revokedByInUse': False, + 'revokedOnInUse': False, + 'revocationReasonInUse': False, + 'issuedByInUse': False, + 'issuedOnInUse': False, + 'validNotBeforeInUse': False, + 'validNotAfterInUse': False, + 'validityLengthInUse': False, + 'certTypeInUse': False} + + if options.get('exactly', False): + booloptions['matchExactly'] = True + + if 'subject' in options: + node = etree.SubElement(page, 'commonName') + node.text = options['subject'] + booloptions['subjectInUse'] = True + + if 'revocation_reason' in options: + node = etree.SubElement(page, 'revocationReason') + node.text = unicode(options['revocation_reason']) + booloptions['revocationReasonInUse'] = True + + if 'min_serial_number' in options: + node = etree.SubElement(page, 'serialFrom') + node.text = unicode(options['min_serial_number']) + + if 'max_serial_number' in options: + node = etree.SubElement(page, 'serialTo') + node.text = unicode(options['max_serial_number']) + + # date_types is a tuple that consists of: + # 1. attribute name passed from IPA API + # 2. attribute name used by REST API + # 3. boolean to set in the REST API + + date_types = ( + ('validnotbefore_from', 'validNotBeforeFrom', 'validNotBeforeInUse'), + ('validnotbefore_to', 'validNotBeforeTo', 'validNotBeforeInUse'), + ('validnotafter_from', 'validNotAfterFrom', 'validNotAfterInUse'), + ('validnotafter_to', 'validNotAfterTo', 'validNotAfterInUse'), + ('issuedon_from', 'issuedOnFrom','issuedOnInUse'), + ('issuedon_to', 'issuedOnTo','issuedOnInUse'), + ('revokedon_from', 'revokedOnFrom','revokedOnInUse'), + ('revokedon_to', 'revokedOnTo','revokedOnInUse'), + ) + + for (attr, dattr, battr) in date_types: + if attr in options: + epoch = convert_time(options[attr]) + node = etree.SubElement(page, dattr) + node.text = unicode(epoch) + booloptions[battr] = True + + # Add the boolean options to our XML document + for opt in booloptions: + e = etree.SubElement(page, opt) + e.text = str(booloptions[opt]).lower() + + payload = etree.tostring(doc, pretty_print=False, xml_declaration=True, encoding='UTF-8') + self.debug('%s.find(): request: %s', self.fullname, payload) + + url = 'http://%s/ca/rest/certs/search?size=%d' % (ipautil.format_netloc(self.ca_host, ipapython.dogtag.configured_constants().UNSECURE_PORT), options.get('sizelimit', 100)) + + opener = urllib2.build_opener() + opener.addheaders = [('Accept-Encoding', 'gzip, deflate'), + ('User-Agent', 'IPA')] + + req = urllib2.Request(url=url, data=payload, headers={'Content-Type': 'application/xml'}) + try: + response = opener.open(req) + except urllib2.HTTPError, e: + self.raise_certificate_operation_error('find', + detail=e.msg) + except urllib2.URLError, e: + self.raise_certificate_operation_error('find', + detail=e.reason) + + data = response.readlines() + self.debug('%s.find(): response: %s', self.fullname, data) + parser = etree.XMLParser() + try: + doc = etree.fromstring(data[0], parser) + except etree.XMLSyntaxError, e: + self.raise_certificate_operation_error('find', + detail=e.msg) + + # Grab all the certificates + certs = doc.xpath('//CertDataInfo') + + results = [] + + for cert in certs: + response_request = {} + response_request['serial_number'] = int(cert.get('id'), 16) # parse as hex + response_request['serial_number_hex'] = u'0x%X' % response_request['serial_number'] + + dn = cert.xpath('SubjectDN') + if len(dn) == 1: + response_request['subject'] = unicode(dn[0].text) + status = cert.xpath('Status') + if len(status) == 1: + response_request['status'] = unicode(status[0].text) + results.append(response_request) + + return results + api.register(ra) diff --git a/ipaserver/plugins/rabase.py b/ipaserver/plugins/rabase.py index 369027b43..1d8713f4a 100644 --- a/ipaserver/plugins/rabase.py +++ b/ipaserver/plugins/rabase.py @@ -111,3 +111,11 @@ class rabase(Backend): """ raise errors.NotImplementedError(name='%s.take_certificate_off_hold' % self.name) + + def find(self, options): + """ + Search for certificates + + :param options: dictionary of search options + """ + raise errors.NotImplementedError(name='%s.find' % self.name) diff --git a/tests/test_xmlrpc/test_cert.py b/tests/test_xmlrpc/test_cert.py index 4f95ffe19..906d1977a 100644 --- a/tests/test_xmlrpc/test_cert.py +++ b/tests/test_xmlrpc/test_cert.py @@ -1,7 +1,7 @@ # Authors: # Rob Crittenden <rcritten@redhat.com> # -# Copyright (C) 2009 Red Hat +# Copyright (C) 2009,2013 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ Test the `ipalib/plugins/cert.py` module against the selfsign plugin. import sys import os import shutil -from nose.tools import assert_raises # pylint: disable=E0611 +from nose.tools import raises, assert_raises # pylint: disable=E0611 from xmlrpc_test import XMLRPC_test, assert_attr_equal from ipalib import api @@ -39,29 +39,50 @@ from ipapython.dn import DN cert = None newcert = None +def is_db_configured(): + """ + Raise an exception if we are testing against lite-server and the + developer cert database is configured. + """ + aliasdir = api.env.dot_ipa + os.sep + 'alias' + os.sep + '.pwd' + + if (api.env.xmlrpc_uri == u'http://localhost:8888/ipa/xml' and + not ipautil.file_exists(aliasdir)): + raise nose.SkipTest('developer CA not configured in %s' % aliasdir) + # Test setup # # This test needs a configured CA behind it in order to work properly -# It currently specifically tests for a self-signed CA but there is no -# reason the test wouldn't work with a dogtag CA as well with some -# additional work. This will change when selfsign is no longer the default CA. # -# To set it up grab the 3 NSS db files from a self-signed CA from -# /etc/httpd/alias to ~/.ipa/alias. Copy /etc/httpd/alias/pwdfile.txt to -# ~/.ipa/alias/.pwd. Change ownership of these files too. That should do it. +# To test against Apache directly then no changes are required. Just be +# sure the xmlrpc_uri in ~/.ipa/default.conf points to Apache. +# +# To test against a selfsign or dogtag CA in the lite-server: +# +# - Copy the 3 NSS db files from /etc/httpd/alias to ~/.ipa/alias +# - Copy /etc/httpd/alias/pwdfile.txt to ~/.ipa/alias/.pwd. +# - Change ownership of these files to be readable by you. +# +# The API tested depends on the value of ~/.ipa/default/ra_plugin when +# running as the lite-server. class test_cert(XMLRPC_test): + @classmethod + def setUpClass(cls): + super(test_cert, cls).setUpClass() + + if 'cert_request' not in api.Command: + raise nose.SkipTest('cert_request not registered') + + is_db_configured() + def run_certutil(self, args, stdin=None): new_args = ["/usr/bin/certutil", "-d", self.reqdir] new_args = new_args + args return ipautil.run(new_args, stdin) def setUp(self): - if 'cert_request' not in api.Command: - raise nose.SkipTest('cert_request not registered') - if not ipautil.file_exists(api.env.dot_ipa + os.sep + 'alias' + os.sep + '.pwd'): - raise nose.SkipTest('developer self-signed CA not configured') super(test_cert, self).setUp() self.reqdir = tempfile.mkdtemp(prefix = "tmp-") self.reqfile = self.reqdir + "/test.csr" @@ -99,7 +120,7 @@ class test_cert(XMLRPC_test): host_fqdn = u'ipatestcert.%s' % api.env.domain service_princ = u'test/%s@%s' % (host_fqdn, api.env.realm) - def test_1_cert_add(self): + def test_0001_cert_add(self): """ Test the `xmlrpc.cert_request` method without --add. @@ -112,7 +133,7 @@ class test_cert(XMLRPC_test): with assert_raises(errors.NotFound): res = api.Command['cert_request'](csr, principal=self.service_princ) - def test_2_cert_add(self): + def test_0002_cert_add(self): """ Test the `xmlrpc.cert_request` method with --add. """ @@ -125,7 +146,7 @@ class test_cert(XMLRPC_test): # save the cert for the service_show/find tests cert = res['certificate'] - def test_3_service_show(self): + def test_0003_service_show(self): """ Verify that service-show has the right certificate using service-show. """ @@ -134,7 +155,7 @@ class test_cert(XMLRPC_test): res = api.Command['service_show'](self.service_princ)['result'] assert base64.b64encode(res['usercertificate'][0]) == cert - def test_4_service_find(self): + def test_0004_service_find(self): """ Verify that service-find has the right certificate using service-find. """ @@ -144,7 +165,7 @@ class test_cert(XMLRPC_test): res = api.Command['service_find'](self.service_princ)['result'] assert base64.b64encode(res[0]['usercertificate'][0]) == cert - def test_5_cert_renew(self): + def test_0005_cert_renew(self): """ Issue a new certificate for a service """ @@ -156,7 +177,7 @@ class test_cert(XMLRPC_test): # save the cert for the service_show/find tests newcert = res['certificate'] - def test_6_service_show(self): + def test_0006_service_show(self): """ Verify the new certificate with service-show. """ @@ -168,7 +189,7 @@ class test_cert(XMLRPC_test): # And it should match the new one assert base64.b64encode(res['usercertificate'][0]) == newcert - def test_7_cleanup(self): + def test_0007_cleanup(self): """ Clean up cert test data """ @@ -178,3 +199,256 @@ class test_cert(XMLRPC_test): # Verify that the service is gone res = api.Command['service_find'](self.service_princ) assert res['count'] == 0 + +class test_cert_find(XMLRPC_test): + + @classmethod + def setUpClass(cls): + super(test_cert_find, cls).setUpClass() + + if 'cert_find' not in api.Command: + raise nose.SkipTest('cert_find not registered') + + if api.env.ra_plugin != 'dogtag': + raise nose.SkipTest('cert_find for dogtag CA only') + + is_db_configured() + + """ + Test the `cert-find` command. + """ + short = api.env.host.replace('.' + api.env.domain, '') + + def test_0001_find_all(self): + """ + Search for all certificates. + + We don't know how many we'll get but there should be at least 10 + by default. + """ + res = api.Command['cert_find']() + assert 'count' in res and res['count'] >= 10 + + def test_0002_find_CA(self): + """ + Search for the CA certificate. + """ + res = api.Command['cert_find'](subject=u'Certificate Authority') + assert 'count' in res and res['count'] == 1 + + def test_0003_find_OCSP(self): + """ + Search for the OCSP certificate. + """ + res = api.Command['cert_find'](subject=u'OCSP Subsystem') + + def test_0004_find_this_host(self): + """ + Find all certificates for this IPA server + """ + res = api.Command['cert_find'](subject=api.env.host) + assert 'count' in res and res['count'] > 1 + + def test_0005_find_this_host_exact(self): + """ + Find all certificates for this IPA server (exact) + """ + res = api.Command['cert_find'](subject=api.env.host, exactly=True) + assert 'count' in res and res['count'] > 1 + + def test_0006_find_this_short_host_exact(self): + """ + Find all certificates for this IPA server short name (exact) + """ + res = api.Command['cert_find'](subject=self.short, exactly=True) + assert 'count' in res and res['count'] == 0 + + def test_0007_find_revocation_reason_0(self): + """ + Find all certificates with revocation reason 0 + """ + res = api.Command['cert_find'](revocation_reason=0) + assert 'count' in res and res['count'] == 0 + + def test_0008_find_revocation_reason_1(self): + """ + Find all certificates with revocation reason 1 + """ + res = api.Command['cert_find'](revocation_reason=1) + assert 'count' in res and res['count'] == 0 + + def test_0009_find_revocation_reason_2(self): + """ + Find all certificates with revocation reason 2 + """ + res = api.Command['cert_find'](revocation_reason=2) + assert 'count' in res and res['count'] == 0 + + def test_0010_find_revocation_reason_3(self): + """ + Find all certificates with revocation reason 3 + """ + res = api.Command['cert_find'](revocation_reason=3) + assert 'count' in res and res['count'] == 0 + + def test_0011_find_revocation_reason_4(self): + """ + Find all certificates with revocation reason 4 + + There is no way to know in advance how many revoked certificates + we'll have but in the context of make-test we'll have at least one. + """ + res = api.Command['cert_find'](revocation_reason=4) + assert 'count' in res and res['count'] >= 1 + + def test_0012_find_revocation_reason_5(self): + """ + Find all certificates with revocation reason 5 + """ + res = api.Command['cert_find'](revocation_reason=5) + assert 'count' in res and res['count'] == 0 + + def test_0013_find_revocation_reason_6(self): + """ + Find all certificates with revocation reason 6 + """ + res = api.Command['cert_find'](revocation_reason=6) + assert 'count' in res and res['count'] == 0 + + # There is no revocation reason #7 + + def test_0014_find_revocation_reason_8(self): + """ + Find all certificates with revocation reason 8 + """ + res = api.Command['cert_find'](revocation_reason=8) + assert 'count' in res and res['count'] == 0 + + def test_0015_find_revocation_reason_9(self): + """ + Find all certificates with revocation reason 9 + """ + res = api.Command['cert_find'](revocation_reason=9) + assert 'count' in res and res['count'] == 0 + + def test_0016_find_revocation_reason_10(self): + """ + Find all certificates with revocation reason 10 + """ + res = api.Command['cert_find'](revocation_reason=10) + assert 'count' in res and res['count'] == 0 + + def test_0017_find_by_issuedon(self): + """ + Find all certificates issued since 2008 + """ + res = api.Command['cert_find'](issuedon_from=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 10 + + def test_0018_find_through_issuedon(self): + """ + Find all certificates issued through 2008 + """ + res = api.Command['cert_find'](issuedon_to=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 0 + + def test_0019_find_notvalid_before(self): + """ + Find all certificates valid not before 2008 + """ + res = api.Command['cert_find'](validnotbefore_from=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 10 + + def test_0020_find_notvalid_before(self): + """ + Find all certificates valid not before to 2100 + """ + res = api.Command['cert_find'](validnotbefore_to=u'2100-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 10 + + def test_0021_find_notvalid_before(self): + """ + Find all certificates valid not before 2100 + """ + res = api.Command['cert_find'](validnotbefore_from=u'2100-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 0 + + def test_0022_find_notvalid_before(self): + """ + Find all certificates valid not before to 2008 + """ + res = api.Command['cert_find'](validnotbefore_to=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 0 + + def test_0023_find_notvalid_after(self): + """ + Find all certificates valid not after 2008 + """ + res = api.Command['cert_find'](validnotafter_from=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 10 + + def test_0024_find_notvalid_after(self): + """ + Find all certificates valid not after to 2100 + """ + res = api.Command['cert_find'](validnotafter_to=u'2100-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 10 + + def test_0025_find_notvalid_after(self): + """ + Find all certificates valid not after 2100 + """ + res = api.Command['cert_find'](validnotafter_from=u'2100-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 0 + + def test_0026_find_notvalid_after(self): + """ + Find all certificates valid not after to 2008 + """ + res = api.Command['cert_find'](validnotafter_to=u'2008-01-01', + sizelimit=10) + assert 'count' in res and res['count'] == 0 + + def test_0027_sizelimit_zero(self): + """ + Search with a sizelimit of 0 + """ + res = api.Command['cert_find'](sizelimit=0) + assert 'count' in res and res['count'] == 0 + + @raises(errors.ValidationError) + def test_0028_find_negative_size(self): + """ + Search with a negative sizelimit + """ + res = api.Command['cert_find'](sizelimit=-100) + + def test_0029_search_for_notfound(self): + """ + Search for a host that isn't there. + """ + res = api.Command['cert_find'](subject=u'notfound') + assert 'count' in res and res['count'] == 0 + + def test_0030_search_for_testcerts(self): + """ + Search for certs created in other tests + """ + res = api.Command['cert_find'](subject=u'ipatestcert.%s' % api.env.domain) + assert 'count' in res and res['count'] >= 1 + + @raises(errors.ValidationError) + def test_0031_search_on_invalid_date(self): + """ + Search using invalid date format + """ + res = api.Command['cert_find'](issuedon_from=u'xyz') |