summaryrefslogtreecommitdiffstats
path: root/ipalib/plugins/certprofile.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib/plugins/certprofile.py')
-rw-r--r--ipalib/plugins/certprofile.py253
1 files changed, 253 insertions, 0 deletions
diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py
new file mode 100644
index 000000000..1a2d14388
--- /dev/null
+++ b/ipalib/plugins/certprofile.py
@@ -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)