[Freeipa-devel] [PATCH] 0026..0027 #5096 enforce caacl for SAN principals

Fraser Tweedale ftweedal at redhat.com
Fri Jul 3 14:26:39 UTC 2015


The attached patches fix:

- a bug that caused caacl false negatives for hosts principals
- #5096 cert-request: enforce caacl for subjectAltName principals

Thanks,
Fraser
-------------- next part --------------
From f6d7f8e58a7fcb09261ae18a8722f28da778779c Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Fri, 3 Jul 2015 10:05:40 -0400
Subject: [PATCH 26/27] caacl: fix incorrect construction of HbacRequest for
 hosts

The _acl_make_request function is using the 'host/' prefix itself
instead of the hostname after it.  Use split_any_principal to do the
splitting correctly, also taking realm into account.
---
 ipalib/plugins/caacl.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
index 6bf39d2330c8999726484e1e9fb44fdb7c755767..247d6df143aef1fba9f0ee74a9f7d8386bef5180 100644
--- a/ipalib/plugins/caacl.py
+++ b/ipalib/plugins/caacl.py
@@ -55,13 +55,15 @@ register = Registry()
 
 def _acl_make_request(principal_type, principal, ca_ref, profile_id):
     """Construct HBAC request for the given principal, CA and profile"""
+    service, name, realm = split_any_principal(principal)
+
     req = pyhbac.HbacRequest()
     req.targethost.name = ca_ref
     req.service.name = profile_id
     if principal_type == 'user':
         req.user.name = principal
     elif principal_type == 'host':
-        req.user.name = principal[:5]  # strip 'host/'
+        req.user.name = name
     elif principal_type == 'service':
         req.user.name = normalize_principal(principal)
     groups = []
@@ -70,8 +72,7 @@ def _acl_make_request(principal_type, principal, ca_ref, profile_id):
         groups = user_obj.get('memberof_group', [])
         groups += user_obj.get('memberofindirect_group', [])
     elif principal_type == 'host':
-        service, hostname, realm = split_any_principal(principal)
-        host_obj = api.Command.host_show(hostname)['result']
+        host_obj = api.Command.host_show(name)['result']
         groups = host_obj.get('memberof_hostgroup', [])
         groups += host_obj.get('memberofindirect_hostgroup', [])
     req.user.groups = sorted(set(groups))
-- 
2.1.0

-------------- next part --------------
From c39c0f122310f070997c058aefc5617ca75a7ff2 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Fri, 3 Jul 2015 10:15:19 -0400
Subject: [PATCH 27/27] cert-request: enforce caacl for principals in SAN

cert-request currently does not enforce caacls for principals
included in the subjectAltName requestExtension.  Enforce for any
dNSName values recognised as hosts/services known to FreeIPA.

Fixes: https://fedorahosted.org/freeipa/ticket/5096
---
 ipalib/plugins/cert.py | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py
index 1878e5ad5f80fa93e1a77b0a88711c1da0016681..743fb4d3930f051c4a2098128b09b241a844cb43 100644
--- a/ipalib/plugins/cert.py
+++ b/ipalib/plugins/cert.py
@@ -220,6 +220,22 @@ def ca_enabled_check():
     if not api.Command.ca_is_enabled()['result']:
         raise errors.NotFound(reason=_('CA is not configured'))
 
+def caacl_check(principal_type, principal_string, ca, profile_id):
+    principal_type_map = {USER: 'user', HOST: 'host', SERVICE: 'service'}
+    if not ipalib.plugins.caacl.acl_evaluate(
+            principal_type_map[principal_type],
+            principal_string, ca, profile_id):
+        raise errors.ACIError(info=_(
+                "Principal '%(principal)s' "
+                "is not permitted to use CA '%(ca)s' "
+                "with profile '%(profile_id)s' for certificate issuance."
+            ) % dict(
+                principal=principal_string,
+                ca=ca or '.',
+                profile_id=profile_id
+            )
+        )
+
 @register()
 class cert_request(VirtualCommand):
     __doc__ = _('Submit a certificate signing request.')
@@ -305,6 +321,7 @@ class cert_request(VirtualCommand):
         add = kw.get('add')
         request_type = kw.get('request_type')
         profile_id = kw.get('profile_id', self.Backend.ra.DEFAULT_PROFILE)
+        ca = '.'  # top-level CA hardcoded until subca plugin implemented
 
         """
         Access control is partially handled by the ACI titled
@@ -327,21 +344,7 @@ class cert_request(VirtualCommand):
         else:
             principal_type = SERVICE
 
-        principal_type_map = {USER: 'user', HOST: 'host', SERVICE: 'service'}
-        ca = '.'  # top-level CA hardcoded until subca plugin implemented
-        if not ipalib.plugins.caacl.acl_evaluate(
-                principal_type_map[principal_type],
-                principal_string, ca, profile_id):
-            raise errors.ACIError(info=_(
-                    "Principal '%(principal)s' "
-                    "is not permitted to use CA '%(ca)s' "
-                    "with profile '%(profile_id)s' for certificate issuance."
-                ) % dict(
-                    principal=principal_string,
-                    ca=ca or '.',
-                    profile_id=profile_id
-                )
-            )
+        caacl_check(principal_type, principal_string, ca, profile_id)
 
         bind_principal = split_any_principal(getattr(context, 'principal'))
         bind_service, bind_name, bind_realm = bind_principal
@@ -439,13 +442,15 @@ class cert_request(VirtualCommand):
             if name_type == pkcs10.SAN_DNSNAME:
                 name = unicode(name)
                 alt_principal_obj = None
+                alt_principal_string = None
                 try:
                     if principal_type == HOST:
+                        alt_principal_string = 'host/%s@%s' % (name, realm)
                         alt_principal_obj = api.Command['host_show'](name, all=True)
                     elif principal_type == SERVICE:
-                        altprincipal = '%s/%s@%s' % (servicename, name, realm)
+                        alt_principal_string = '%s/%s@%s' % (servicename, name, realm)
                         alt_principal_obj = api.Command['service_show'](
-                            altprincipal, all=True)
+                            alt_principal_string, all=True)
                     elif principal_type == USER:
                         raise errors.ValidationError(
                             name='csr',
@@ -465,6 +470,9 @@ class cert_request(VirtualCommand):
                         raise errors.ACIError(info=_(
                             "Insufficient privilege to create a certificate "
                             "with subject alt name '%s'.") % name)
+                if alt_principal_string is not None:
+                    caacl_check(
+                        principal_type, alt_principal_string, ca, profile_id)
             elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME,
                                pkcs10.SAN_OTHERNAME_UPN):
                 if name != principal_string:
-- 
2.1.0



More information about the Freeipa-devel mailing list