diff options
-rw-r--r-- | ACI.txt | 8 | ||||
-rw-r--r-- | API.txt | 64 | ||||
-rw-r--r-- | VERSION | 4 | ||||
-rw-r--r-- | install/conf/ipa-pki-proxy.conf | 4 | ||||
-rw-r--r-- | install/share/60certificate-profiles.ldif | 4 | ||||
-rw-r--r-- | install/share/bootstrap-template.ldif | 6 | ||||
-rw-r--r-- | install/updates/41-lightweight-cas.update | 4 | ||||
-rw-r--r-- | install/updates/Makefile.am | 1 | ||||
-rw-r--r-- | ipalib/constants.py | 2 | ||||
-rw-r--r-- | ipaserver/install/cainstance.py | 7 | ||||
-rw-r--r-- | ipaserver/install/server/upgrade.py | 16 | ||||
-rw-r--r-- | ipaserver/plugins/ca.py | 217 | ||||
-rw-r--r-- | ipaserver/plugins/dogtag.py | 54 |
13 files changed, 385 insertions, 6 deletions
@@ -22,6 +22,14 @@ dn: cn=automount,dc=ipa,dc=example aci: (targetattr = "automountmapname || description")(targetfilter = "(objectclass=automountmap)")(version 3.0;acl "permission:System: Modify Automount Maps";allow (write) groupdn = "ldap:///cn=System: Modify Automount Maps,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=automount,dc=ipa,dc=example aci: (targetfilter = "(objectclass=automountmap)")(version 3.0;acl "permission:System: Remove Automount Maps";allow (delete) groupdn = "ldap:///cn=System: Remove Automount Maps,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=cas,cn=ca,dc=ipa,dc=example +aci: (targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Add CA";allow (add) groupdn = "ldap:///cn=System: Add CA,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=cas,cn=ca,dc=ipa,dc=example +aci: (targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Delete CA";allow (delete) groupdn = "ldap:///cn=System: Delete CA,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=cas,cn=ca,dc=ipa,dc=example +aci: (targetattr = "cn || description")(targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Modify CA";allow (write) groupdn = "ldap:///cn=System: Modify CA,cn=permissions,cn=pbac,dc=ipa,dc=example";) +dn: cn=cas,cn=ca,dc=ipa,dc=example +aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacaid || ipacaissuerdn || ipacasubjectdn || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Read CAs";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=caacls,cn=ca,dc=ipa,dc=example aci: (targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Add CA ACL";allow (add) groupdn = "ldap:///cn=System: Add CA ACL,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=caacls,cn=ca,dc=ipa,dc=example @@ -450,12 +450,76 @@ arg: Any('methods*') option: Str('version?') output: Output('count', type=[<type 'int'>]) output: Output('results', type=[<type 'list'>, <type 'tuple'>]) +command: ca_add +args: 1,7,3 +arg: Str('cn', cli_name='name') +option: Str('addattr*', cli_name='addattr') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('description?', cli_name='desc') +option: DNParam('ipacasubjectdn', cli_name='subject') +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('setattr*', cli_name='setattr') +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) +output: PrimaryKey('value') +command: ca_del +args: 1,2,3 +arg: Str('cn+', cli_name='name') +option: Flag('continue', autofill=True, cli_name='continue', default=False) +option: Str('version?') +output: Output('result', type=[<type 'dict'>]) +output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) +output: ListOfPrimaryKeys('value') +command: ca_find +args: 1,11,4 +arg: Str('criteria?') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('cn?', autofill=False, cli_name='name') +option: Str('description?', autofill=False, cli_name='desc') +option: Str('ipacaid?', autofill=False, cli_name='id') +option: DNParam('ipacaissuerdn?', autofill=False, cli_name='issuer') +option: DNParam('ipacasubjectdn?', autofill=False, cli_name='subject') +option: Flag('pkey_only?', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Int('sizelimit?', autofill=False) +option: Int('timelimit?', autofill=False) +option: Str('version?') +output: Output('count', type=[<type 'int'>]) +output: ListOfEntries('result') +output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) +output: Output('truncated', type=[<type 'bool'>]) command: ca_is_enabled args: 0,1,3 option: Str('version?') output: Output('result', type=[<type 'bool'>]) output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: PrimaryKey('value') +command: ca_mod +args: 1,9,3 +arg: Str('cn', cli_name='name') +option: Str('addattr*', cli_name='addattr') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('delattr*', cli_name='delattr') +option: Str('description?', autofill=False, cli_name='desc') +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('rename?', cli_name='rename') +option: Flag('rights', autofill=True, default=False) +option: Str('setattr*', cli_name='setattr') +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) +output: PrimaryKey('value') +command: ca_show +args: 1,4,3 +arg: Str('cn', cli_name='name') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Flag('rights', autofill=True, default=False) +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) +output: PrimaryKey('value') command: caacl_add args: 1,12,3 arg: Str('cn', cli_name='name') @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=180 -# Last change: mbabink - Server Roles: provide an API for setting CA renewal master +IPA_API_VERSION_MINOR=181 +# Last change: ftweedal - add lightweight CAs plugin diff --git a/install/conf/ipa-pki-proxy.conf b/install/conf/ipa-pki-proxy.conf index 4b5b6f727..545f21253 100644 --- a/install/conf/ipa-pki-proxy.conf +++ b/install/conf/ipa-pki-proxy.conf @@ -1,4 +1,4 @@ -# VERSION 8 - DO NOT REMOVE THIS LINE +# VERSION 9 - DO NOT REMOVE THIS LINE ProxyRequests Off @@ -27,7 +27,7 @@ ProxyRequests Off </LocationMatch> # matches for CA REST API -<LocationMatch "^/ca/rest/account/login|^/ca/rest/account/logout|^/ca/rest/installer/installToken|^/ca/rest/securityDomain/domainInfo|^/ca/rest/securityDomain/installToken|^/ca/rest/profiles|^/ca/rest/admin/kraconnector/remove"> +<LocationMatch "^/ca/rest/account/login|^/ca/rest/account/logout|^/ca/rest/installer/installToken|^/ca/rest/securityDomain/domainInfo|^/ca/rest/securityDomain/installToken|^/ca/rest/profiles|^/ca/rest/authorities|^/ca/rest/admin/kraconnector/remove"> NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient optional ProxyPassMatch ajp://localhost:$DOGTAG_PORT diff --git a/install/share/60certificate-profiles.ldif b/install/share/60certificate-profiles.ldif index 798c3a3b0..a87fe667d 100644 --- a/install/share/60certificate-profiles.ldif +++ b/install/share/60certificate-profiles.ldif @@ -4,5 +4,9 @@ attributeTypes: (2.16.840.1.113730.3.8.21.1.2 NAME 'ipaMemberCa' DESC 'Reference attributeTypes: (2.16.840.1.113730.3.8.21.1.3 NAME 'ipaMemberCertProfile' DESC 'Reference to a certificate profile member' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v4.2' ) attributeTypes: (2.16.840.1.113730.3.8.21.1.4 NAME 'ipaCaCategory' DESC 'Additional classification for CAs' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.2' ) attributeTypes: (2.16.840.1.113730.3.8.21.1.5 NAME 'ipaCertProfileCategory' DESC 'Additional classification for certificate profiles' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.2' ) +attributeTypes: (2.16.840.1.113730.3.8.21.1.6 NAME 'ipaCaId' DESC 'Dogtag Authority ID' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.4 Lightweight CAs' ) +attributeTypes: (2.16.840.1.113730.3.8.21.1.7 NAME 'ipaCaIssuerDN' DESC 'Issuer DN' SUP distinguishedName X-ORIGIN 'IPA v4.4 Lightweight CAs' ) +attributeTypes: (2.16.840.1.113730.3.8.21.1.8 NAME 'ipaCaSubjectDN' DESC 'Subject DN' SUP distinguishedName X-ORIGIN 'IPA v4.4 Lightweight CAs' ) objectClasses: (2.16.840.1.113730.3.8.21.2.1 NAME 'ipaCertProfile' SUP top STRUCTURAL MUST ( cn $ description $ ipaCertProfileStoreIssued ) X-ORIGIN 'IPA v4.2' ) objectClasses: (2.16.840.1.113730.3.8.21.2.2 NAME 'ipaCaAcl' SUP ipaAssociation STRUCTURAL MUST cn MAY ( ipaCaCategory $ ipaCertProfileCategory $ userCategory $ hostCategory $ serviceCategory $ ipaMemberCa $ ipaMemberCertProfile $ memberService ) X-ORIGIN 'IPA v4.2' ) +objectClasses: (2.16.840.1.113730.3.8.21.2.3 NAME 'ipaCa' SUP top STRUCTURAL MUST ( cn $ ipaCaId $ ipaCaSubjectDN $ ipaCaIssuerDN ) MAY description X-ORIGIN 'IPA v4.4 Lightweight CAs' ) diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif index f6ab35495..da12ddf0c 100644 --- a/install/share/bootstrap-template.ldif +++ b/install/share/bootstrap-template.ldif @@ -476,3 +476,9 @@ changetype: add objectClass: nsContainer objectClass: top cn: caacls + +dn: cn=cas,cn=ca,$SUFFIX +changetype: add +objectClass: nsContainer +objectClass: top +cn: cas diff --git a/install/updates/41-lightweight-cas.update b/install/updates/41-lightweight-cas.update new file mode 100644 index 000000000..72313e2ab --- /dev/null +++ b/install/updates/41-lightweight-cas.update @@ -0,0 +1,4 @@ +dn: cn=cas,cn=ca,$SUFFIX +default: objectClass: nsContainer +default: objectClass: top +default: cn: cas diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am index fde69175c..455fd209d 100644 --- a/install/updates/Makefile.am +++ b/install/updates/Makefile.am @@ -39,6 +39,7 @@ app_DATA = \ 40-otp.update \ 40-vault.update \ 41-caacl.update \ + 41-lightweight-cas.update \ 45-roles.update \ 50-7_bit_check.update \ 50-dogtag10-migration.update \ diff --git a/ipalib/constants.py b/ipalib/constants.py index 97dff1d80..05ba1adbb 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -122,6 +122,7 @@ DEFAULT_CONFIG = ( ('container_topology', DN(('cn', 'topology'), ('cn', 'ipa'), ('cn', 'etc'))), ('container_caacl', DN(('cn', 'caacls'), ('cn', 'ca'))), ('container_locations', DN(('cn', 'locations'), ('cn', 'etc'))), + ('container_ca', DN(('cn', 'cas'), ('cn', 'ca'))), # Ports, hosts, and URIs: ('xmlrpc_uri', 'http://localhost:8888/ipa/xml'), @@ -265,3 +266,4 @@ REPL_AGMT_STRIP_ATTRS = ('modifiersName', DOMAIN_SUFFIX_NAME = 'domain' CA_SUFFIX_NAME = 'ca' PKI_GSSAPI_SERVICE_NAME = 'dogtag' +IPA_CA_CN = u'ipa' diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index becb0b172..3e2576d05 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -1629,6 +1629,13 @@ def ensure_ldap_profiles_container(): ou=['certificateProfiles'], ) +def ensure_lightweight_cas_container(): + ensure_entry( + DN(('ou', 'authorities'), ('ou', 'ca'), ('o', 'ipaca')), + objectclass=['top', 'organizationalUnit'], + ou=['authorities'], + ) + def ensure_entry(dn, **attrs): server_id = installutils.realm_to_serverid(api.env.realm) diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py index cd2ad2e11..81a49e8af 100644 --- a/ipaserver/install/server/upgrade.py +++ b/ipaserver/install/server/upgrade.py @@ -345,6 +345,16 @@ def ca_import_included_profiles(ca): return cainstance.import_included_profiles() +def ca_ensure_lightweight_cas_container(ca): + root_logger.info('[Ensuring Lightweight CAs container exists in Dogtag database]') + + if not ca.is_configured(): + root_logger.info('CA is not configured') + return False + + return cainstance.ensure_lightweight_cas_container() + + def upgrade_ca_audit_cert_validity(ca): """ Update the Dogtag audit signing certificate. @@ -1438,7 +1448,10 @@ def ca_upgrade_schema(ca): root_logger.info('CA is not configured') return False - schema_files=['/usr/share/pki/server/conf/schema-certProfile.ldif'] + schema_files=[ + '/usr/share/pki/server/conf/schema-certProfile.ldif', + '/usr/share/pki/server/conf/schema-authority.ldif', + ] try: modified = schemaupdate.update_schema(schema_files, ldapi=True) except Exception as e: @@ -1698,6 +1711,7 @@ def upgrade_configuration(): except ipautil.CalledProcessError as e: root_logger.error("Failed to restart %s: %s", ca.service_name, e) + ca_ensure_lightweight_cas_container(ca) ca_enable_ldap_profile_subsystem(ca) # This step MUST be done after ca_enable_ldap_profile_subsystem and diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py new file mode 100644 index 000000000..ee98f0a2a --- /dev/null +++ b/ipaserver/plugins/ca.py @@ -0,0 +1,217 @@ +# +# Copyright (C) 2016 FreeIPA Contributors see COPYING for license +# + +from ipalib import api, errors, DNParam, Str +from ipalib.constants import IPA_CA_CN +from ipalib.plugable import Registry +from ipaserver.plugins.baseldap import ( + LDAPObject, LDAPSearch, LDAPCreate, LDAPDelete, + LDAPUpdate, LDAPRetrieve) +from ipaserver.plugins.cert import ca_enabled_check +from ipalib import _, ngettext + + +__doc__ = _(""" +Manage Certificate Authorities + +Subordinate Certificate Authorities (Sub-CAs) can be added for scoped issuance +of X.509 certificates. + +EXAMPLES: + + Create new CA, subordinate to the IPA CA. + + ipa ca-add puppet --desc "Puppet" \\ + --subject "CN=Puppet CA,O=EXAMPLE.COM" + +""") + + +register = Registry() + + +@register() +class ca(LDAPObject): + """ + Lightweight CA Object + """ + container_dn = api.env.container_ca + object_name = _('Certificate Authority') + object_name_plural = _('Certificate Authorities') + object_class = ['ipaca'] + permission_filter_objectclasses = ['ipaca'] + default_attributes = [ + 'cn', 'description', 'ipacaid', 'ipacaissuerdn', 'ipacasubjectdn', + ] + rdn_attribute = 'cn' + rdn_is_primary_key = True + label = _('Certificate Authorities') + label_singular = _('Certificate Authority') + + takes_params = ( + Str('cn', + primary_key=True, + cli_name='name', + label=_('Name'), + doc=_('Name for referencing the CA'), + ), + Str('description?', + cli_name='desc', + label=_('Description'), + doc=_('Description of the purpose of the CA'), + ), + Str('ipacaid', + cli_name='id', + label=_('Authority ID'), + doc=_('Dogtag Authority ID'), + flags=['no_create', 'no_update'], + ), + DNParam('ipacasubjectdn', + cli_name='subject', + label=_('Subject DN'), + doc=_('Subject Distinguished Name'), + flags=['no_update'], + ), + DNParam('ipacaissuerdn', + cli_name='issuer', + label=_('Issuer DN'), + doc=_('Issuer Distinguished Name'), + flags=['no_create', 'no_update'], + ), + ) + + permission_filter_objectclasses = ['ipaca'] + managed_permissions = { + 'System: Read CAs': { + 'replaces_global_anonymous_aci': True, + 'ipapermbindruletype': 'all', + 'ipapermright': {'read', 'search', 'compare'}, + 'ipapermdefaultattr': { + 'cn', + 'description', + 'ipacaid', + 'ipacaissuerdn', + 'ipacasubjectdn', + 'objectclass', + }, + }, + 'System: Add CA': { + 'ipapermright': {'add'}, + 'replaces': [ + '(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Add CA";allow (add) groupdn = "ldap:///cn=Add CA,cn=permissions,cn=pbac,$SUFFIX";)', + ], + 'default_privileges': {'CA Administrator'}, + }, + 'System: Delete CA': { + 'ipapermright': {'delete'}, + 'replaces': [ + '(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete CA";allow (delete) groupdn = "ldap:///cn=Delete CA,cn=permissions,cn=pbac,$SUFFIX";)', + ], + 'default_privileges': {'CA Administrator'}, + }, + 'System: Modify CA': { + 'ipapermright': {'write'}, + 'ipapermdefaultattr': { + 'cn', + 'description', + }, + 'replaces': [ + '(targetattr = "cn || description")(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify CA";allow (write) groupdn = "ldap:///cn=Modify CA,cn=permissions,cn=pbac,$SUFFIX";)', + ], + 'default_privileges': {'CA Administrator'}, + }, + } + + +@register() +class ca_find(LDAPSearch): + __doc__ = _("Search for CAs.") + msg_summary = ngettext( + '%(count)d CA matched', '%(count)d CAs matched', 0 + ) + + def execute(self, *keys, **options): + ca_enabled_check() + return super(ca_find, self).execute(*keys, **options) + + +@register() +class ca_show(LDAPRetrieve): + __doc__ = _("Display the properties of a CA.") + + def execute(self, *args, **kwargs): + ca_enabled_check() + return super(ca_show, self).execute(*args, **kwargs) + + +@register() +class ca_add(LDAPCreate): + __doc__ = _("Create a CA.") + msg_summary = _('Created CA "%(value)s"') + + def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options): + ca_enabled_check() + if not ldap.can_add(dn[1:]): + raise errors.ACIError( + info=_("Insufficient 'add' privilege for entry '%s'.") % dn) + + # check for name collision before creating CA in Dogtag + try: + api.Object.ca.get_dn_if_exists(keys[-1]) + self.obj.handle_duplicate_entry(*keys) + except errors.NotFound: + pass + + # Create the CA in Dogtag. + with self.api.Backend.ra_lightweight_ca as ca_api: + resp = ca_api.create_ca(options['ipacasubjectdn']) + entry['ipacaid'] = [resp['id']] + entry['ipacaissuerdn'] = [resp['issuerDN']] + + # In the event that the issued certificate's subject DN + # differs from what was requested, record the actual DN. + # + entry['ipacasubjectdn'] = [resp['dn']] + return dn + + +@register() +class ca_del(LDAPDelete): + __doc__ = _('Delete a CA.') + + msg_summary = _('Deleted CA "%(value)s"') + + def pre_callback(self, ldap, dn, *keys, **options): + ca_enabled_check() + + if keys[0] == IPA_CA_CN: + raise errors.ProtectedEntryError( + label=_("CA"), + key=keys[0], + reason=_("IPA CA cannot be deleted")) + + ca_id = self.api.Command.ca_show(keys[0])['result']['ipacaid'][0] + with self.api.Backend.ra_lightweight_ca as ca_api: + ca_api.disable_ca(ca_id) + ca_api.delete_ca(ca_id) + + return dn + + +@register() +class ca_mod(LDAPUpdate): + __doc__ = _("Modify CA configuration.") + msg_summary = _('Modified CA "%(value)s"') + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + ca_enabled_check() + + if 'rename' in options or 'cn' in entry_attrs: + if keys[0] == IPA_CA_CN: + raise errors.ProtectedEntryError( + label=_("CA"), + key=keys[0], + reason=u'IPA CA cannot be renamed') + + return dn diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py index 197814c4d..20349b05f 100644 --- a/ipaserver/plugins/dogtag.py +++ b/ipaserver/plugins/dogtag.py @@ -2073,7 +2073,10 @@ class RestClient(Backend): headers = headers or {} headers['Cookie'] = self.cookie - resource = os.path.join('/ca/rest', self.path, path) + if path is not None: + resource = os.path.join('/ca/rest', self.path, path) + else: + resource = os.path.join('/ca/rest', self.path) # perform main request status, resp_headers, resp_body = dogtag.https_request( @@ -2147,3 +2150,52 @@ class ra_certprofile(RestClient): Delete the profile from Dogtag """ self._ssldo('DELETE', profile_id, headers={'Accept': 'application/json'}) + + +@register() +class ra_lightweight_ca(RestClient): + """ + Lightweight CA management backend plugin. + """ + path = 'authorities' + + def create_ca(self, dn): + """Create CA with the given DN. + + New CA is issued by IPA CA. Nested sub-CAs and unrelated + root CAs are not yet supported. + + Return the (parsed) JSON response from server. + + """ + + assert isinstance(dn, DN) + status, resp_headers, resp_body = self._ssldo( + 'POST', None, + headers={ + 'Content-type': 'application/json', + 'Accept': 'application/json', + }, + body=json.dumps({"parentID": "host-authority", "dn": unicode(dn)}), + ) + try: + return json.loads(resp_body) + except: + raise errors.RemoteRetrieveError(reason=_("Response from CA was not valid JSON")) + + def read_ca(self, ca_id): + status, resp_headers, resp_body = self._ssldo( + 'GET', ca_id, headers={'Accept': 'application/json'}) + try: + return json.loads(resp_body) + except: + raise errors.RemoteRetrieveError(reason=_("Response from CA was not valid JSON")) + + def disable_ca(self, ca_id): + self._ssldo( + 'POST', ca_id + '/disable', + headers={'Accept': 'application/json'}, + ) + + def delete_ca(self, ca_id): + self._ssldo('DELETE', ca_id) |