Add certprofile plugin

Add the 'certprofile' plugin which defines the commands for managing
certificate profiles and associated permissions.

Also update Dogtag network code in 'ipapython.dogtag' to support
headers and arbitrary request bodies, to facilitate use of the
Dogtag profiles REST API.

Part of: https://fedorahosted.org/freeipa/ticket/57

Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Fraser Tweedale
2015-04-30 04:55:29 -04:00
committed by Jan Cholasta
parent 35af0d6d66
commit 300b74fc7f
9 changed files with 534 additions and 13 deletions

View File

@@ -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=certprofiles,cn=ca,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Delete Certificate Profile";allow (delete) groupdn = "ldap:///cn=System: Delete Certificate Profile,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certprofiles,cn=ca,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Import Certificate Profile";allow (add) groupdn = "ldap:///cn=System: Import Certificate Profile,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certprofiles,cn=ca,dc=ipa,dc=example
aci: (targetattr = "cn || description || ipacertprofilestoreissued")(targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Modify Certificate Profile";allow (write) groupdn = "ldap:///cn=System: Modify Certificate Profile,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certprofiles,cn=ca,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacertprofilestoreissued || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Read Certificate Profiles";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=ipaconfig,cn=etc,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=costemplates,cn=accounts,dc=ipa,dc=example

62
API.txt
View File

@@ -509,6 +509,68 @@ args: 1,1,1
arg: Str('request_id')
option: Str('version?', exclude='webui')
output: Output('result', None, None)
command: certprofile_del
args: 1,2,3
arg: Str('cn', attribute=True, cli_name='id', multivalue=True, primary_key=True, query=True, required=True)
option: Flag('continue', autofill=True, cli_name='continue', default=False)
option: Str('version?', exclude='webui')
output: Output('result', <type 'dict'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: ListOfPrimaryKeys('value', None, None)
command: certprofile_find
args: 1,9,4
arg: Str('criteria?', noextrawhitespace=False)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Str('cn', attribute=True, autofill=False, cli_name='id', multivalue=False, primary_key=True, query=True, required=False)
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False)
option: Bool('ipacertprofilestoreissued', attribute=True, autofill=False, cli_name='store', default=True, multivalue=False, query=True, required=False)
option: Flag('pkey_only?', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Int('sizelimit?', autofill=False, minvalue=0)
option: Int('timelimit?', autofill=False, minvalue=0)
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: certprofile_import
args: 1,6,3
arg: Str('cn', attribute=True, cli_name='id', multivalue=False, primary_key=True, required=True)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=True)
option: File('file', cli_name='file')
option: Bool('ipacertprofilestoreissued', attribute=True, cli_name='store', default=True, multivalue=False, required=True)
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: certprofile_mod
args: 1,10,3
arg: Str('cn', attribute=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Str('delattr*', cli_name='delattr', exclude='webui')
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False)
option: Bool('ipacertprofilestoreissued', attribute=True, autofill=False, cli_name='store', default=True, multivalue=False, required=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('rename', cli_name='rename', multivalue=False, primary_key=True, required=False)
option: Flag('rights', autofill=True, default=False)
option: Str('setattr*', cli_name='setattr', exclude='webui')
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: certprofile_show
args: 1,4,3
arg: Str('cn', attribute=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Flag('rights', autofill=True, default=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: compat_is_enabled
args: 0,1,1
option: Str('version?', exclude='webui')

View File

@@ -0,0 +1,9 @@
dn: cn=ca,$SUFFIX
default: objectClass: nsContainer
default: objectClass: top
default: cn: ca
dn: cn=certprofiles,cn=ca,$SUFFIX
default: objectClass: nsContainer
default: objectClass: top
default: cn: certprofiles

View File

@@ -237,3 +237,11 @@ default:ipapermissiontype: SYSTEM
dn: cn=config
add:aci: (version 3.0;acl "permission:Add Configuration Sub-Entries";allow (add) groupdn = "ldap:///cn=Add Configuration Sub-Entries,cn=permissions,cn=pbac,$SUFFIX";)
# CA Administrators
dn: cn=CA Administrator,cn=privileges,cn=pbac,$SUFFIX
default:objectClass: nestedgroup
default:objectClass: groupofnames
default:objectClass: top
default:cn: CA Administrator
default:description: CA Administrator

View File

@@ -32,6 +32,7 @@ app_DATA = \
40-replication.update \
40-dns.update \
40-automember.update \
40-certprofile.update \
40-otp.update \
40-vault.update \
45-roles.update \

View File

@@ -118,6 +118,7 @@ DEFAULT_CONFIG = (
('container_radiusproxy', DN(('cn', 'radiusproxy'))),
('container_views', DN(('cn', 'views'), ('cn', 'accounts'))),
('container_masters', DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'))),
('container_certprofile', DN(('cn', 'certprofiles'), ('cn', 'ca'))),
# Ports, hosts, and URIs:
('xmlrpc_uri', 'http://localhost:8888/ipa/xml'),

View File

@@ -0,0 +1,253 @@
#
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
import re
from ipalib import api, Bool, File, Str
from ipalib import output
from ipalib.plugable import Registry
from ipalib.plugins.virtual import VirtualCommand
from ipalib.plugins.baseldap import (
LDAPObject, LDAPSearch, LDAPCreate,
LDAPDelete, LDAPUpdate, LDAPRetrieve)
from ipalib import ngettext
from ipalib.text import _
from ipalib import errors
__doc__ = _("""
Manage Certificate Profiles
Certificate Profiles are used by Certificate Authority (CA) in the signing of
certificates to determine if a Certificate Signing Request (CSR) is acceptable,
and if so what features and extensions will be present on the certificate.
The Certificate Profile format is the property-list format understood by the
Dogtag or Red Hat Certificate System CA.
PROFILE ID SYNTAX:
A Profile ID is a string without spaces or punctuation starting with a letter
and followed by a sequence of letters, digits or underscore ("_").
EXAMPLES:
Import a profile that will not store issued certificates:
ipa certprofile-import ShortLivedUserCert \\
--file UserCert.profile --summary "User Certificates" \\
--store=false
Delete a certificate profile:
ipa certprofile-del ShortLivedUserCert
Show information about a profile:
ipa certprofile-show ShortLivedUserCert
Search for profiles that do not store certificates:
ipa certprofile-find --store=false
""")
register = Registry()
def ca_enabled_check():
"""Raise NotFound if CA is not enabled.
This function is defined in multiple plugins to avoid circular imports
(cert depends on certprofile, so we cannot import cert here).
"""
if not api.Command.ca_is_enabled()['result']:
raise errors.NotFound(reason=_('CA is not configured'))
profile_id_pattern = re.compile('^[a-zA-Z]\w*$')
def validate_profile_id(ugettext, value):
"""Ensure profile ID matches form required by CA."""
if profile_id_pattern.match(value) is None:
return _('invalid Profile ID')
else:
return None
@register()
class certprofile(LDAPObject):
"""
Certificate Profile object.
"""
container_dn = api.env.container_certprofile
object_name = _('Certificate Profile')
object_name_plural = _('Certificate Profiles')
object_class = ['ipacertprofile']
default_attributes = [
'cn', 'description', 'ipacertprofilestoreissued'
]
search_attributes = [
'cn', 'description', 'ipacertprofilestoreissued'
]
rdn_is_primary_key = True
label = _('Certificate Profiles')
label_singular = _('Certificate Profile')
takes_params = (
Str('cn', validate_profile_id,
primary_key=True,
cli_name='id',
label=_('Profile ID'),
doc=_('Profile ID for referring to this profile'),
),
Str('description',
required=True,
cli_name='desc',
label=_('Profile description'),
doc=_('Brief description of this profile'),
),
Bool('ipacertprofilestoreissued',
default=True,
cli_name='store',
label=_('Store issued certificates'),
doc=_('Whether to store certs issued using this profile'),
),
)
permission_filter_objectclasses = ['ipacertprofile']
managed_permissions = {
'System: Read Certificate Profiles': {
'replaces_global_anonymous_aci': True,
'ipapermbindruletype': 'all',
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
'cn',
'description',
'ipacertprofilestoreissued',
'objectclass',
},
},
'System: Import Certificate Profile': {
'ipapermright': {'add'},
'replaces': [
'(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Import Certificate Profile";allow (add) groupdn = "ldap:///cn=Import Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)',
],
'default_privileges': {'CA Administrator'},
},
'System: Delete Certificate Profile': {
'ipapermright': {'delete'},
'replaces': [
'(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete Certificate Profile";allow (delete) groupdn = "ldap:///cn=Delete Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)',
],
'default_privileges': {'CA Administrator'},
},
'System: Modify Certificate Profile': {
'ipapermright': {'write'},
'ipapermdefaultattr': {
'cn',
'description',
'ipacertprofilestoreissued',
},
'replaces': [
'(targetattr = "cn || description || ipacertprofilestoreissued")(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify Certificate Profile";allow (write) groupdn = "ldap:///cn=Modify Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)',
],
'default_privileges': {'CA Administrator'},
},
}
@register()
class certprofile_find(LDAPSearch):
__doc__ = _("Search for Certificate Profiles.")
msg_summary = ngettext(
'%(count)d profile matched', '%(count)d profiles matched', 0
)
def execute(self, *args, **kwargs):
ca_enabled_check()
return super(certprofile_find, self).execute(*args, **kwargs)
@register()
class certprofile_show(LDAPRetrieve):
__doc__ = _("Display the properties of a Certificate Profile.")
def execute(self, *args, **kwargs):
ca_enabled_check()
return super(certprofile_show, self).execute(*args, **kwargs)
@register()
class certprofile_import(LDAPCreate):
__doc__ = _("Import a Certificate Profile.")
msg_summary = _('Imported profile "%(value)s"')
takes_options = (
File('file',
label=_('Filename'),
cli_name='file',
flags=('virtual_attribute',),
),
)
PROFILE_ID_PATTERN = re.compile('^profileId=([a-zA-Z]\w*)', re.MULTILINE)
def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options):
ca_enabled_check()
match = self.PROFILE_ID_PATTERN.search(options['file'])
if match is None:
raise errors.ValidationError(name='file',
error=_("Profile ID is not present in profile data"))
elif keys[0] != match.group(1):
raise errors.ValidationError(name='file',
error=_("Profile ID '%(cli_value)s' does not match profile data '%(file_value)s'")
% {'cli_value': keys[0], 'file_value': match.group(1)}
)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
"""Import the profile into Dogtag and enable it.
If the operation succeeds, update the LDAP entry to 'enabled'.
If the operation fails, remove the LDAP entry.
"""
try:
with self.api.Backend.ra_certprofile as profile_api:
profile_api.create_profile(options['file'])
profile_api.enable_profile(keys[0])
except:
# something went wrong ; delete entry
ldap.delete_entry(dn)
raise
return dn
@register()
class certprofile_del(LDAPDelete):
__doc__ = _("Delete a Certificate Profile.")
msg_summary = _('Deleted profile "%(value)s"')
def execute(self, *args, **kwargs):
ca_enabled_check()
return super(certprofile_del, self).execute(*args, **kwargs)
def post_callback(self, ldap, dn, *keys, **options):
with self.api.Backend.ra_certprofile as profile_api:
profile_api.disable_profile(keys[0])
profile_api.delete_profile(keys[0])
return dn
@register()
class certprofile_mod(LDAPUpdate):
__doc__ = _("Modify Certificate Profile configuration.")
msg_summary = _('Modified Certificate Profile "%(value)s')
def execute(self, *args, **kwargs):
ca_enabled_check()
return super(certprofile_mod, self).execute(*args, **kwargs)

View File

@@ -233,9 +233,12 @@ def ca_status(ca_host=None, use_proxy=True):
return _parse_ca_status(body)
def https_request(host, port, url, secdir, password, nickname, **kw):
def https_request(host, port, url, secdir, password, nickname,
method='POST', headers=None, body=None, **kw):
"""
:param method: HTTP request method (defalut: 'POST')
:param url: The path (not complete URL!) to post to.
:param body: The request body (encodes kw if None)
:param kw: Keyword arguments to encode into POST body.
:return: (http_status, http_reason_phrase, http_headers, http_body)
as (integer, unicode, dict, str)
@@ -254,9 +257,11 @@ def https_request(host, port, url, secdir, password, nickname, **kw):
nickname, password, nss.get_default_certdb())
return conn
body = urlencode(kw)
if body is None:
body = urlencode(kw)
return _httplib_request(
'https', host, port, url, connection_factory, body)
'https', host, port, url, connection_factory, body,
method=method, headers=headers)
def http_request(host, port, url, **kw):
@@ -288,11 +293,13 @@ def unauthenticated_https_request(host, port, url, **kw):
def _httplib_request(
protocol, host, port, path, connection_factory, request_body):
protocol, host, port, path, connection_factory, request_body,
method='POST', headers=None):
"""
:param request_body: Request body
:param connection_factory: Connection class to use. Will be called
with the host and port arguments.
:param method: HTTP request method (default: 'POST')
Perform a HTTP(s) request.
"""
@@ -301,13 +308,17 @@ def _httplib_request(
uri = '%s://%s%s' % (protocol, ipautil.format_netloc(host, port), path)
root_logger.debug('request %r', uri)
root_logger.debug('request body %r', request_body)
headers = headers or {}
if (
method == 'POST'
and 'content-type' not in (str(k).lower() for k in headers.viewkeys())
):
headers['content-type'] = 'application/x-www-form-urlencoded'
try:
conn = connection_factory(host, port)
conn.request(
'POST', uri,
body=request_body,
headers={'Content-type': 'application/x-www-form-urlencoded'},
)
conn.request(method, uri, body=request_body, headers=headers)
res = conn.getresponse()
http_status = res.status

View File

@@ -4,8 +4,9 @@
# Jason Gerard DeRose <jderose@redhat.com>
# Rob Crittenden <rcritten@@redhat.com>
# John Dennis <jdennis@redhat.com>
# Fraser Tweedale <ftweedal@redhat.com>
#
# Copyright (C) 2014 Red Hat
# Copyright (C) 2014, 2015 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
@@ -238,17 +239,21 @@ digits and nothing else follows.
'''
import datetime
import json
from lxml import etree
import os
import tempfile
import time
import urllib2
import pki
from pki.client import PKIConnection
import pki.crypto as cryptoutil
from pki.kra import KRAClient
from ipalib import Backend
from ipapython.dn import DN
import ipapython.cookie
import ipapython.dogtag
from ipapython import ipautil
from ipaserver.install.certs import CertDB
@@ -1262,13 +1267,12 @@ def select_any_master(ldap2, service='CA'):
#-------------------------------------------------------------------------------
from ipalib import api, SkipPluginModule
from ipalib import api, errors, SkipPluginModule
if api.env.ra_plugin != 'dogtag':
# In this case, abort loading this plugin module...
raise SkipPluginModule(reason='dogtag not selected as RA plugin')
import os, random
from ipaserver.plugins import rabase
from ipalib.errors import CertificateOperationError
from ipalib.constants import TYPE_ERROR
from ipalib.util import cachedproperty
from ipapython import dogtag
@@ -1318,7 +1322,7 @@ class ra(rabase.rabase):
err_msg = u'%s (%s)' % (err_msg, detail)
self.error('%s.%s(): %s', self.fullname, func_name, err_msg)
raise CertificateOperationError(error=err_msg)
raise errors.CertificateOperationError(error=err_msg)
@cachedproperty
def ca_host(self):
@@ -1923,3 +1927,167 @@ class kra(Backend):
return KRAClient(connection, crypto)
api.register(kra)
class RestClient(Backend):
"""Simple Dogtag REST client to be subclassed by other backends.
This class is a context manager. Authenticated calls must be
executed in a ``with`` suite::
class ra_certprofile(RestClient):
path = 'profile'
...
api.register(ra_certprofile)
with api.Backend.ra_certprofile as profile_api:
# REST client is now logged in
profile_api.create_profile(...)
"""
path = None
@staticmethod
def _parse_dogtag_error(body):
try:
return pki.PKIException.from_json(json.loads(body))
except:
return None
def __init__(self):
if api.env.in_tree:
self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
self.pwd_file = self.sec_dir + os.sep + '.pwd'
else:
self.sec_dir = paths.HTTPD_ALIAS_DIR
self.pwd_file = paths.ALIAS_PWDFILE_TXT
self.noise_file = self.sec_dir + os.sep + '.noise'
self.ipa_key_size = "2048"
self.ipa_certificate_nickname = "ipaCert"
self.ca_certificate_nickname = "caCert"
try:
f = open(self.pwd_file, "r")
self.password = f.readline().strip()
f.close()
except IOError:
self.password = ''
super(RestClient, self).__init__()
# session cookie
self.cookie = None
@cachedproperty
def ca_host(self):
"""
:return: host
as str
Select our CA host.
"""
ldap2 = self.api.Backend.ldap2
if host_has_service(api.env.ca_host, ldap2, "CA"):
return api.env.ca_host
if api.env.host != api.env.ca_host:
if host_has_service(api.env.host, ldap2, "CA"):
return api.env.host
host = select_any_master(ldap2)
if host:
return host
else:
return api.env.ca_host
def __enter__(self):
"""Log into the REST API"""
if self.cookie is not None:
return
status, status_text, resp_headers, resp_body = dogtag.https_request(
self.ca_host, self.env.ca_agent_port, '/ca/rest/account/login',
self.sec_dir, self.password, self.ipa_certificate_nickname,
method='GET'
)
cookies = ipapython.cookie.Cookie.parse(resp_headers.get('set-cookie', ''))
if status != 200 or len(cookies) == 0:
raise errors.RemoteRetrieveError(reason=_('Failed to authenticate to CA REST API'))
self.cookie = str(cookies[0])
return self
def __exit__(self, exc_type, exc_value, traceback):
"""Log out of the REST API"""
dogtag.https_request(
self.ca_host, self.env.ca_agent_port, '/ca/rest/account/logout',
self.sec_dir, self.password, self.ipa_certificate_nickname,
method='GET'
)
self.cookie = None
def _ssldo(self, method, path, headers=None, body=None):
"""
:param url: The URL to post to.
:param kw: Keyword arguments to encode into POST body.
:return: (http_status, http_reason_phrase, http_headers, http_body)
as (integer, unicode, dict, str)
Perform an HTTPS request
"""
if self.cookie is None:
raise errors.RemoteRetrieveError(
reason=_("REST API is not logged in."))
headers = headers or {}
headers['Cookie'] = self.cookie
resource = os.path.join('/ca/rest', self.path, path)
# perform main request
status, status_text, resp_headers, resp_body = dogtag.https_request(
self.ca_host, self.env.ca_agent_port, resource,
self.sec_dir, self.password, self.ipa_certificate_nickname,
method=method, headers=headers, body=body
)
if status < 200 or status >= 300:
explanation = self._parse_dogtag_error(resp_body) or ''
raise errors.RemoteRetrieveError(
reason=_('Non-2xx response from CA REST API: %(status)d %(status_text)s. %(explanation)s')
% {'status': status, 'status_text': status_text, 'explanation': explanation}
)
return (status, status_text, resp_headers, resp_body)
class ra_certprofile(RestClient):
"""
Profile management backend plugin.
"""
path = 'profiles'
def create_profile(self, profile_data):
"""
Import the profile into Dogtag
"""
self._ssldo('POST', 'raw',
headers={
'Content-type': 'application/xml',
'Accept': 'application/json',
},
body=profile_data
)
def enable_profile(self, profile_id):
"""
Enable the profile in Dogtag
"""
self._ssldo('POST', profile_id + '?action=enable')
def disable_profile(self, profile_id):
"""
Enable the profile in Dogtag
"""
self._ssldo('POST', profile_id + '?action=disable')
def delete_profile(self, profile_id):
"""
Delete the profile from Dogtag
"""
self._ssldo('DELETE', profile_id, headers={'Accept': 'application/json'})
api.register(ra_certprofile)