summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--API.txt23
-rw-r--r--VERSION2
-rw-r--r--ipalib/plugins/cert.py137
-rw-r--r--ipaserver/plugins/dogtag.py138
-rw-r--r--ipaserver/plugins/rabase.py8
-rw-r--r--tests/test_xmlrpc/test_cert.py312
6 files changed, 598 insertions, 22 deletions
diff --git a/API.txt b/API.txt
index 8473fbbc5..9437cd4b8 100644
--- a/API.txt
+++ b/API.txt
@@ -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')
diff --git a/VERSION b/VERSION
index 60431df5b..27fbc08d1 100644
--- a/VERSION
+++ b/VERSION
@@ -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')