[Freeipa-devel] [PATCHES 00012-0013 v7] Profiles and CA ACLs
Fraser Tweedale
ftweedal at redhat.com
Mon Jun 8 01:31:22 UTC 2015
New patches attached. Comments inline.
On Thu, Jun 04, 2015 at 03:40:18PM +0200, Martin Basti wrote:
> Hello,
>
> design page needs upgrade
>
> Please fix
> 1)
> ngettext/ugettext missing? (several times)
> ('%i object added.', '%i objects added.')
>
Updated, and customed to say the actual things being added/removed.
There seem to be many plugins still without internationalised
`member_count_out' strings.
> 2)
> --allprofiles=BOOL Allow use of all profiles
> --allusers=BOOL Allow all users
> --allhosts=BOOL Allow all hosts
> --allservices=BOOL Allow all services
>
> Other commands use the separate words with '-', I suggest to use
> --all-profiles=True, etc..
>
Subsumed by (4).
> 3)
> In the following example, there is missing ACL name:
> + ipa caacl-add-user --user=alice
>
Thanks, fixed.
> 4)
> attributes 'ipaCaAclAllCAs', 'ipaCaAclAllProfiles', 'ipaCaAclAllUsers',
> 'ipaCaAclAllHosts', 'ipaCaAclAllServices' should be called
> ipaCaAclCAsCategory, etc... to be consistent, please reuse usercategory,
> hostcategory, etc. and create new category attribute definitions for the
> rest.
> Please read sudorule.py for details.
> Respectively instead BOOLEAN True, the value 'all' should be there. This
> allows to extend it in future.
>
I made this change. Accordingly there is less schema now - but some
new attributes 'caCategory', 'profileCategory', 'memberCa' and
'memberProfile' - and more code :)
> 5)
> Missing referint plugin configuration for attribute
> 'ipacaaclmembercertprofile'
> Please add it into install/updates/25-referint.update (+ other member
> attributes if missing)
>
Added this. There is a comment in 25-referint.update:
# pres and eq indexes defined in 20-indices.update must be set
# for all the attributes
Can you explain what is required here? Is it just to add: I see
things for memberUser and memberHost in indices.ldif but nothing for
memberService. Do I need to add to indices.ldif:
dn: cn=memberProfile,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
changetype: add
cn: memberProfile
ObjectClass: top
ObjectClass: nsIndex
nsSystemIndex: false
nsIndexType: eq
nsIndexType: pres
nsIndexType: sub
, and similarly for memberCa? Sorry I do not know much about LDAP
indexing.
> 6)
> ACI:
> 'memberhostgroup' is not virtual nor real attribute, please remove it from
> there (Honza told me there is an error in HBAC ipa plugin, I will send fix)
>
Removed.
Thanks for reviewing!
Fraser
-------------- next part --------------
From c8ca3e613487fa8f14ded1533588872205bbe1de Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 25 May 2015 08:39:07 -0400
Subject: [PATCH 12/13] Add CA ACL plugin
Implement the caacl commands, which are used to indicate which
principals may be issued certificates from which (sub-)CAs, using
which profiles.
At this commit, and until sub-CAs are implemented, all rules refer
to the top-level CA (represented as ".") and no ca-ref argument is
exposed.
Also add a default CA ACL that permits certificate issuance for all
hosts and services using the profile 'caIPAserviceCert' on the
top-level CA. This rule is added during install but not upgrade.
Part of: https://fedorahosted.org/freeipa/ticket/57
Part of: https://fedorahosted.org/freeipa/ticket/4559
---
ACI.txt | 10 +
API.txt | 184 ++++++++++++
VERSION | 4 +-
install/share/60certificate-profiles.ldif | 5 +
install/share/Makefile.am | 1 +
install/share/bootstrap-template.ldif | 6 +
install/share/default-caacl.ldif | 11 +
install/updates/25-referint.update | 2 +
install/updates/41-caacl.update | 4 +
install/updates/Makefile.am | 1 +
ipalib/constants.py | 1 +
ipalib/plugins/caacl.py | 476 ++++++++++++++++++++++++++++++
ipaserver/install/dsinstance.py | 4 +
13 files changed, 707 insertions(+), 2 deletions(-)
create mode 100644 install/share/default-caacl.ldif
create mode 100644 install/updates/41-caacl.update
create mode 100644 ipalib/plugins/caacl.py
diff --git a/ACI.txt b/ACI.txt
index 59173ac1b593f15e079c7b1fce43ec9b0084ec91..bf63cb4caac09fb9d9697290e31afdee0a364882 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -22,6 +22,16 @@ 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=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
+aci: (targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Delete CA ACL";allow (delete) groupdn = "ldap:///cn=System: Delete CA ACL,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: cn=caacls,cn=ca,dc=ipa,dc=example
+aci: (targetattr = "cacategory || hostcategory || memberca || memberhost || memberprofile || memberservice || memberuser || profilecategory || servicecategory || usercategory")(targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Manage CA ACL Membership";allow (write) groupdn = "ldap:///cn=System: Manage CA ACL Membership,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: cn=caacls,cn=ca,dc=ipa,dc=example
+aci: (targetattr = "cn || description || ipaenabledflag")(targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Modify CA ACL";allow (write) groupdn = "ldap:///cn=System: Modify CA ACL,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: cn=caacls,cn=ca,dc=ipa,dc=example
+aci: (targetattr = "cacategory || cn || createtimestamp || description || entryusn || hostcategory || ipaenabledflag || ipauniqueid || member || memberca || memberhost || memberprofile || memberservice || memberuser || modifytimestamp || objectclass || profilecategory || servicecategory || usercategory")(targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Read CA ACLs";allow (compare,read,search) userdn = "ldap:///all";)
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
diff --git a/API.txt b/API.txt
index eca4e302021316f9b02e543a9dc8b029286696cc..5263aa61f0981410534d28bf2ddde9020a971834 100644
--- a/API.txt
+++ b/API.txt
@@ -456,6 +456,190 @@ option: Str('version?', exclude='webui')
output: Output('result', <type 'bool'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
+command: caacl_add
+args: 1,12,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=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('description', attribute=True, cli_name='desc', multivalue=False, required=False)
+option: StrEnum('hostcategory', attribute=True, cli_name='hostcat', multivalue=False, required=False, values=(u'all',))
+option: Bool('ipaenabledflag', attribute=True, cli_name='ipaenabledflag', multivalue=False, required=False)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: StrEnum('profilecategory', attribute=True, cli_name='profilecat', multivalue=False, required=False, values=(u'all',))
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: StrEnum('servicecategory', attribute=True, cli_name='servicecat', multivalue=False, required=False, values=(u'all',))
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: StrEnum('usercategory', attribute=True, cli_name='usercat', multivalue=False, required=False, values=(u'all',))
+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: caacl_add_host
+args: 1,6,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True)
+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_add_profile
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('certprofile*', alwaysask=True, cli_name='certprofiles', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_add_service
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('service*', alwaysask=True, cli_name='services', csv=True)
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_add_user
+args: 1,6,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_del
+args: 1,2,3
+arg: Str('cn', attribute=True, cli_name='name', 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: caacl_disable
+args: 1,1,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: caacl_enable
+args: 1,1,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: caacl_find
+args: 1,14,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='name', 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: StrEnum('hostcategory', attribute=True, autofill=False, cli_name='hostcat', multivalue=False, query=True, required=False, values=(u'all',))
+option: Bool('ipaenabledflag', attribute=True, autofill=False, cli_name='ipaenabledflag', multivalue=False, query=True, required=False)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('pkey_only?', autofill=True, default=False)
+option: StrEnum('profilecategory', attribute=True, autofill=False, cli_name='profilecat', multivalue=False, query=True, required=False, values=(u'all',))
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: StrEnum('servicecategory', attribute=True, autofill=False, cli_name='servicecat', multivalue=False, query=True, required=False, values=(u'all',))
+option: Int('sizelimit?', autofill=False, minvalue=0)
+option: Int('timelimit?', autofill=False, minvalue=0)
+option: StrEnum('usercategory', attribute=True, autofill=False, cli_name='usercat', multivalue=False, query=True, required=False, values=(u'all',))
+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: caacl_mod
+args: 1,14,3
+arg: Str('cn', attribute=True, cli_name='name', 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: StrEnum('hostcategory', attribute=True, autofill=False, cli_name='hostcat', multivalue=False, required=False, values=(u'all',))
+option: Bool('ipaenabledflag', attribute=True, autofill=False, cli_name='ipaenabledflag', multivalue=False, required=False)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: StrEnum('profilecategory', attribute=True, autofill=False, cli_name='profilecat', multivalue=False, required=False, values=(u'all',))
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: StrEnum('servicecategory', attribute=True, autofill=False, cli_name='servicecat', multivalue=False, required=False, values=(u'all',))
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: StrEnum('usercategory', attribute=True, autofill=False, cli_name='usercat', multivalue=False, required=False, values=(u'all',))
+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: caacl_remove_host
+args: 1,6,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True)
+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_remove_profile
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('certprofile*', alwaysask=True, cli_name='certprofiles', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_remove_service
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('service*', alwaysask=True, cli_name='services', csv=True)
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_remove_user
+args: 1,6,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
+option: Flag('no_members', autofill=True, default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('user*', alwaysask=True, cli_name='users', csv=True)
+option: Str('version?', exclude='webui')
+output: Output('completed', <type 'int'>, None)
+output: Output('failed', <type 'dict'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+command: caacl_show
+args: 1,5,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('no_members', autofill=True, 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: cert_find
args: 0,17,4
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
diff --git a/VERSION b/VERSION
index fe746a7f5c47f02c838763bdda6cb1c61579f6ff..e188a8bc94e29b07eb1fea8c2e2975a1760565c6 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=125
-# Last change: derny - migration now accepts scope as argument
+IPA_API_VERSION_MINOR=126
+# Last change: ftweedal - add caacl plugin
diff --git a/install/share/60certificate-profiles.ldif b/install/share/60certificate-profiles.ldif
index f1281949e53386e5bfe8b35e0c15858c693c5467..aa47c9b5d6b2db885b6273866cdf602df90c2e30 100644
--- a/install/share/60certificate-profiles.ldif
+++ b/install/share/60certificate-profiles.ldif
@@ -1,3 +1,8 @@
dn: cn=schema
attributeTypes: (2.16.840.1.113730.3.8.21.1.1 NAME 'ipaCertProfileStoreIssued' DESC 'Store certificates issued using this profile' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4.2' )
+attributeTypes: (2.16.840.1.113730.3.8.21.1.2 NAME 'memberCa' DESC 'Reference to a CA 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.3 NAME 'memberProfile' 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 'caCategory' 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 'profileCategory' 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' )
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 ( caCategory $ profileCategory $ userCategory $ hostCategory $ serviceCategory $ memberCa $ memberProfile $ memberService ) X-ORIGIN 'IPA v4.2' )
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index 31f391be25c58b76cc71971852074d80c5514745..e97a89ca93f7f188e06dc982bd69e251f8082df3 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -29,6 +29,7 @@ app_DATA = \
bootstrap-template.ldif \
caJarSigningCert.cfg.template \
default-aci.ldif \
+ default-caacl.ldif \
default-hbac.ldif \
default-smb-group.ldif \
default-trust-view.ldif \
diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif
index c5d4bad8b80640881f4631e4873a12c82b0ea48a..2387f220fd4fe6e3ccd59f4b592f2473d7acfa44 100644
--- a/install/share/bootstrap-template.ldif
+++ b/install/share/bootstrap-template.ldif
@@ -441,3 +441,9 @@ changetype: add
objectClass: nsContainer
objectClass: top
cn: certprofiles
+
+dn: cn=caacls,cn=ca,$SUFFIX
+changetype: add
+objectClass: nsContainer
+objectClass: top
+cn: caacls
diff --git a/install/share/default-caacl.ldif b/install/share/default-caacl.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..8acfb489522fe8c66afdc2ed6ac1105f249cd140
--- /dev/null
+++ b/install/share/default-caacl.ldif
@@ -0,0 +1,11 @@
+# default CA ACL that grants use of caIPAserviceCert on top-level CA to all hosts and services
+dn: ipauniqueid=autogenerate,cn=caacls,cn=ca,$SUFFIX
+changetype: add
+objectclass: ipaassociation
+objectclass: ipacaacl
+ipauniqueid: autogenerate
+cn: hosts_services_caIPAserviceCert
+ipaenabledflag: TRUE
+memberprofile: cn=caIPAserviceCert,cn=certprofiles,cn=ca,$SUFFIX
+hostcategory: all
+servicecategory: all
diff --git a/install/updates/25-referint.update b/install/updates/25-referint.update
index 005cd0376d82c83b1b7ab368f992e209b0da5e9a..f173254e189f080e39b29ce214d684b35ae8057a 100644
--- a/install/updates/25-referint.update
+++ b/install/updates/25-referint.update
@@ -17,3 +17,5 @@ add: referint-membership-attr: ipasudorunasgroup
add: referint-membership-attr: ipatokenradiusconfiglink
add: referint-membership-attr: ipaassignedidview
add: referint-membership-attr: ipaallowedtarget
+add: referint-membership-attr: memberca
+add: referint-membership-attr: memberprofile
diff --git a/install/updates/41-caacl.update b/install/updates/41-caacl.update
new file mode 100644
index 0000000000000000000000000000000000000000..a18b6ec946855c194077d9ac01a8adcfddf8542e
--- /dev/null
+++ b/install/updates/41-caacl.update
@@ -0,0 +1,4 @@
+dn: cn=caacls,cn=ca,$SUFFIX
+default: objectClass: nsContainer
+default: objectClass: top
+default: cn: caacls
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index fc6bd624eac619cdddeba29b85440571d85fd69f..eddf4d850ed4b47d5526dc152149fa21b14779d4 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -35,6 +35,7 @@ app_DATA = \
40-certprofile.update \
40-otp.update \
40-vault.update \
+ 41-caacl.update \
45-roles.update \
50-7_bit_check.update \
50-dogtag10-migration.update \
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 93d7aaa7b0b5f0b47b8839e764ef168c1fe08c97..86b1ce8bd501845e7b5871773e86521d3c5d2ad9 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -120,6 +120,7 @@ DEFAULT_CONFIG = (
('container_masters', DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'))),
('container_certprofile', DN(('cn', 'certprofiles'), ('cn', 'ca'))),
('container_topology', DN(('cn', 'topology'), ('cn', 'ipa'), ('cn', 'etc'))),
+ ('container_caacl', DN(('cn', 'caacls'), ('cn', 'ca'))),
# Ports, hosts, and URIs:
('xmlrpc_uri', 'http://localhost:8888/ipa/xml'),
diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
new file mode 100644
index 0000000000000000000000000000000000000000..c589e07b9b211d34239294baeddeee54178c68e6
--- /dev/null
+++ b/ipalib/plugins/caacl.py
@@ -0,0 +1,476 @@
+#
+# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
+#
+
+from ipalib import api, errors, output
+from ipalib import Bool, Str, StrEnum
+from ipalib.plugable import Registry
+from ipalib.plugins.baseldap import (
+ LDAPObject, LDAPSearch, LDAPCreate, LDAPDelete, LDAPQuery,
+ LDAPUpdate, LDAPRetrieve, LDAPAddMember, LDAPRemoveMember,
+ global_output_params, pkey_to_value)
+from ipalib.plugins.hbacrule import is_all
+from ipalib import _, ngettext
+from ipapython.dn import DN
+
+
+__doc__ = _("""
+Manage CA ACL rules.
+
+This plugin is used to define rules governing which principals are
+permitted to have certificates issued using a given certificate
+profile.
+
+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:
+
+ Create a CA ACL "test" that grants all users access to the
+ "UserCert" profile:
+ ipa caacl-add test --usercat=all
+ ipa caacl-add-profile test --certprofiles UserCert
+
+ Display the properties of a named CA ACL:
+ ipa caacl-show test
+
+ Create a CA ACL to let user "alice" use the "DNP3" profile:
+ ipa caacl-add-profile alice_dnp3 --certprofiles DNP3
+ ipa caacl-add-user alice_dnp3 --user=alice
+
+ Disable a CA ACL:
+ ipa caacl-disable test
+
+ Remove a CA ACL:
+ ipa caacl-del test
+""")
+
+register = Registry()
+
+
+ at register()
+class caacl(LDAPObject):
+ """
+ CA ACL object.
+ """
+ container_dn = api.env.container_caacl
+ object_name = _('CA ACL')
+ object_name_plural = _('CA ACLs')
+ object_class = ['ipaassociation', 'ipacaacl']
+ permission_filter_objectclasses = ['ipacaacl']
+ default_attributes = [
+ 'cn', 'description', 'ipaenabledflag',
+ 'cacategory', 'memberca',
+ 'profilecategory', 'memberprofile',
+ 'usercategory', 'memberuser',
+ 'hostcategory', 'memberhost',
+ 'servicecategory', 'memberservice',
+ ]
+ uuid_attribute = 'ipauniqueid'
+ rdn_attribute = 'ipauniqueid'
+ attribute_members = {
+ 'memberuser': ['user', 'group'],
+ 'memberhost': ['host', 'hostgroup'],
+ 'memberservice': ['service'],
+ 'memberprofile': ['certprofile'],
+ }
+ managed_permissions = {
+ 'System: Read CA ACLs': {
+ 'replaces_global_anonymous_aci': True,
+ 'ipapermbindruletype': 'all',
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'cn', 'description', 'ipaenabledflag',
+ 'cacategory', 'memberca',
+ 'profilecategory', 'memberprofile',
+ 'usercategory', 'memberuser',
+ 'hostcategory', 'memberhost',
+ 'servicecategory', 'memberservice',
+ 'ipauniqueid',
+ 'objectclass', 'member',
+ },
+ },
+ 'System: Add CA ACL': {
+ 'ipapermright': {'add'},
+ 'replaces': [
+ '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Add CA ACL";allow (add) groupdn = "ldap:///cn=Add CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'CA Administrator'},
+ },
+ 'System: Delete CA ACL': {
+ 'ipapermright': {'delete'},
+ 'replaces': [
+ '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete CA ACL";allow (delete) groupdn = "ldap:///cn=Delete CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'CA Administrator'},
+ },
+ 'System: Manage CA ACL Membership': {
+ 'ipapermright': {'write'},
+ 'ipapermdefaultattr': {
+ 'cacategory', 'memberca',
+ 'profilecategory', 'memberprofile',
+ 'usercategory', 'memberuser',
+ 'hostcategory', 'memberhost',
+ 'servicecategory', 'memberservice'
+ },
+ 'replaces': [
+ '(targetattr = "memberca || memberprofile || memberuser || memberservice || memberhost || cacategory || profilecategory || usercategory || hostcategory || servicecategory")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Manage CA ACL membership";allow (write) groupdn = "ldap:///cn=Manage CA ACL membership,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'CA Administrator'},
+ },
+ 'System: Modify CA ACL': {
+ 'ipapermright': {'write'},
+ 'ipapermdefaultattr': {
+ 'cn', 'description', 'ipaenabledflag',
+ },
+ 'replaces': [
+ '(targetattr = "cn || description || ipaenabledflag")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify CA ACL";allow (write) groupdn = "ldap:///cn=Modify CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'CA Administrator'},
+ },
+ }
+
+ label = _('CA ACLs')
+ label_singular = _('CA ACL')
+
+ takes_params = (
+ Str('cn',
+ cli_name='name',
+ label=_('ACL name'),
+ primary_key=True,
+ ),
+ Str('description?',
+ cli_name='desc',
+ label=_('Description'),
+ ),
+ Bool('ipaenabledflag?',
+ label=_('Enabled'),
+ flags=['no_option'],
+ ),
+ # Commented until subca plugin arrives
+ #StrEnum('cacategory?',
+ # cli_name='cacat',
+ # label=_('CA category'),
+ # doc=_('CA category the ACL applies to'),
+ # values=(u'all', ),
+ #),
+ StrEnum('profilecategory?',
+ cli_name='profilecat',
+ label=_('Profile category'),
+ doc=_('Profile category the ACL applies to'),
+ values=(u'all', ),
+ ),
+ StrEnum('usercategory?',
+ cli_name='usercat',
+ label=_('User category'),
+ doc=_('User category the ACL applies to'),
+ values=(u'all', ),
+ ),
+ StrEnum('hostcategory?',
+ cli_name='hostcat',
+ label=_('Host category'),
+ doc=_('Host category the ACL applies to'),
+ values=(u'all', ),
+ ),
+ StrEnum('servicecategory?',
+ cli_name='servicecat',
+ label=_('Service category'),
+ doc=_('Service category the ACL applies to'),
+ values=(u'all', ),
+ ),
+ # Commented until subca plugin arrives
+ #Str('memberca_subca?',
+ # label=_('CAs'),
+ # flags=['no_create', 'no_update', 'no_search'],
+ #),
+ Str('memberprofile_certprofile?',
+ label=_('Profiles'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ Str('memberuser_user?',
+ label=_('Users'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ Str('memberuser_group?',
+ label=_('User Groups'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ Str('memberhost_host?',
+ label=_('Hosts'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ Str('memberhost_hostgroup?',
+ label=_('Host Groups'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ Str('memberservice_service?',
+ label=_('Services'),
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ )
+
+
+ at register()
+class caacl_add(LDAPCreate):
+ __doc__ = _('Create a new CA ACL.')
+
+ msg_summary = _('Added CA ACL "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ # CA ACLs are enabled by default
+ entry_attrs['ipaenabledflag'] = ['TRUE']
+ return dn
+
+
+ at register()
+class caacl_del(LDAPDelete):
+ __doc__ = _('Delete a CA ACL.')
+
+ msg_summary = _('Deleted CA ACL "%(value)s"')
+
+
+ at register()
+class caacl_mod(LDAPUpdate):
+ __doc__ = _('Modify a CA ACL.')
+
+ msg_summary = _('Modified CA ACL "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, attrs_list)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+
+ # Commented until subca plugin arrives
+ #if is_all(options, 'cacategory') and 'memberca' in entry_attrs:
+ # raise errors.MutuallyExclusiveError(reason=_(
+ # "CA category cannot be set to 'all' "
+ # "while there are allowed CAs"))
+ if is_all(options, 'profilecategory') and 'memberprofile' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_(
+ "profile category cannot be set to 'all' "
+ "while there are allowed profiles"))
+ if is_all(options, 'usercategory') and 'memberuser' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_(
+ "user category cannot be set to 'all' "
+ "while there are allowed users"))
+ if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_(
+ "host category cannot be set to 'all' "
+ "while there are allowed hosts"))
+ if is_all(options, 'servicecategory') and 'memberservice' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_(
+ "service category cannot be set to 'all' "
+ "while there are allowed services"))
+ return dn
+
+
+ at register()
+class caacl_find(LDAPSearch):
+ __doc__ = _('Search for CA ACLs.')
+
+ msg_summary = ngettext(
+ '%(count)d CA ACL matched', '%(count)d CA ACLs matched', 0
+ )
+
+
+ at register()
+class caacl_show(LDAPRetrieve):
+ __doc__ = _('Display the properties of a CA ACL.')
+
+
+ at register()
+class caacl_enable(LDAPQuery):
+ __doc__ = _('Enable a CA ACL.')
+
+ msg_summary = _('Enabled CA ACL "%(value)s"')
+ has_output = output.standard_value
+
+ def execute(self, cn, **options):
+ ldap = self.obj.backend
+
+ dn = self.obj.get_dn(cn)
+ try:
+ entry_attrs = ldap.get_entry(dn, ['ipaenabledflag'])
+ except errors.NotFound:
+ self.obj.handle_not_found(cn)
+
+ entry_attrs['ipaenabledflag'] = ['TRUE']
+
+ try:
+ ldap.update_entry(entry_attrs)
+ except errors.EmptyModlist:
+ pass
+
+ return dict(
+ result=True,
+ value=pkey_to_value(cn, options),
+ )
+
+
+ at register()
+class caacl_disable(LDAPQuery):
+ __doc__ = _('Disable a CA ACL.')
+
+ msg_summary = _('Disabled CA ACL "%(value)s"')
+ has_output = output.standard_value
+
+ def execute(self, cn, **options):
+ ldap = self.obj.backend
+
+ dn = self.obj.get_dn(cn)
+ try:
+ entry_attrs = ldap.get_entry(dn, ['ipaenabledflag'])
+ except errors.NotFound:
+ self.obj.handle_not_found(cn)
+
+ entry_attrs['ipaenabledflag'] = ['FALSE']
+
+ try:
+ ldap.update_entry(entry_attrs)
+ except errors.EmptyModlist:
+ pass
+
+ return dict(
+ result=True,
+ value=pkey_to_value(cn, options),
+ )
+
+
+ at register()
+class caacl_add_user(LDAPAddMember):
+ __doc__ = _('Add users and groups to a CA ACL.')
+
+ member_attributes = ['memberuser']
+ member_count_out = (
+ _('%i user or group added.'),
+ _('%i users or groups added.'))
+
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if is_all(entry_attrs, 'usercategory'):
+ raise errors.MutuallyExclusiveError(
+ reason=_("users cannot be added when user category='all'"))
+ return dn
+
+
+ at register()
+class caacl_remove_user(LDAPRemoveMember):
+ __doc__ = _('Remove users and groups from a CA ACL.')
+
+ member_attributes = ['memberuser']
+ member_count_out = (
+ _('%i user or group removed.'),
+ _('%i users or groups removed.'))
+
+
+ at register()
+class caacl_add_host(LDAPAddMember):
+ __doc__ = _('Add target hosts and hostgroups to a CA ACL.')
+
+ member_attributes = ['memberhost']
+ member_count_out = (
+ _('%i host or hostgroup added.'),
+ _('%i hosts or hostgroups added.'))
+
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if is_all(entry_attrs, 'hostcategory'):
+ raise errors.MutuallyExclusiveError(
+ reason=_("hosts cannot be added when host category='all'"))
+ return dn
+
+
+ at register()
+class caacl_remove_host(LDAPRemoveMember):
+ __doc__ = _('Remove target hosts and hostgroups from a CA ACL.')
+
+ member_attributes = ['memberhost']
+ member_count_out = (
+ _('%i host or hostgroup removed.'),
+ _('%i hosts or hostgroups removed.'))
+
+
+ at register()
+class caacl_add_service(LDAPAddMember):
+ __doc__ = _('Add services to a CA ACL.')
+
+ member_attributes = ['memberservice']
+ member_count_out = (_('%i service added.'), _('%i services added.'))
+
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if is_all(entry_attrs, 'servicecategory'):
+ raise errors.MutuallyExclusiveError(reason=_(
+ "services cannot be added when service category='all'"))
+ return dn
+
+
+ at register()
+class caacl_remove_service(LDAPRemoveMember):
+ __doc__ = _('Remove services from a CA ACL.')
+
+ member_attributes = ['memberservice']
+ member_count_out = (_('%i service removed.'), _('%i services removed.'))
+
+
+caacl_output_params = global_output_params + (
+ Str('memberprofile',
+ label=_('Failed profiles'),
+ ),
+ # Commented until caacl plugin arrives
+ #Str('memberca',
+ # label=_('Failed CAs'),
+ #),
+)
+
+
+ at register()
+class caacl_add_profile(LDAPAddMember):
+ __doc__ = _('Add profiles to a CA ACL.')
+
+ has_output_params = caacl_output_params
+
+ member_attributes = ['memberprofile']
+ member_count_out = (_('%i profile added.'), _('%i profiles added.'))
+
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, self.obj.default_attributes)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if is_all(entry_attrs, 'profilecategory'):
+ raise errors.MutuallyExclusiveError(reason=_(
+ "profiles cannot be added when profile category='all'"))
+ return dn
+
+
+ at register()
+class caacl_remove_profile(LDAPRemoveMember):
+ __doc__ = _('Remove profiles from a CA ACL.')
+
+ has_output_params = caacl_output_params
+
+ member_attributes = ['memberprofile']
+ member_count_out = (_('%i profile removed.'), _('%i profiles removed.'))
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 2acab13f247ed18a750f0e1cbbd98f4e63718c03..9f24189b6e442e0c55d5de41d15a03f89ecc9578 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -307,6 +307,7 @@ class DsInstance(service.Service):
self.step("adding range check plugin", self.__add_range_check_plugin)
if hbac_allow:
self.step("creating default HBAC rule allow_all", self.add_hbac)
+ self.step("creating default CA ACL rule", self.add_caacl)
self.step("adding entries for topology management", self.__add_topology_entries)
self.__common_post_setup()
@@ -741,6 +742,9 @@ class DsInstance(service.Service):
def add_hbac(self):
self._ldap_mod("default-hbac.ldif", self.sub_dict)
+ def add_caacl(self):
+ self._ldap_mod("default-caacl.ldif", self.sub_dict)
+
def change_admin_password(self, password):
root_logger.debug("Changing admin password")
dirname = config_dirname(self.serverid)
--
2.1.0
-------------- next part --------------
From ad6ba46bb75269604432f7aac6606b88d667537b Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 26 May 2015 04:44:20 -0400
Subject: [PATCH 13/13] Enforce CA ACLs in cert-request command
This commit adds CA ACL enforcement to the cert-request command and
uses the pyhbac machinery.
It is planned to implement ACL enforcement in Dogtag in a future
release, and remove certificate issuance privileges and CA ACL
enforcement responsibility from the framework. See
https://fedorahosted.org/freeipa/ticket/5011 for more information.
Part of: https://fedorahosted.org/freeipa/ticket/57
Part of: https://fedorahosted.org/freeipa/ticket/4559
---
ipalib/plugins/caacl.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
ipalib/plugins/cert.py | 17 +++++++++++
2 files changed, 92 insertions(+)
diff --git a/ipalib/plugins/caacl.py b/ipalib/plugins/caacl.py
index c589e07b9b211d34239294baeddeee54178c68e6..520b506a36474cfb2e29e571fb2c289799c947f6 100644
--- a/ipalib/plugins/caacl.py
+++ b/ipalib/plugins/caacl.py
@@ -2,6 +2,8 @@
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
+import pyhbac
+
from ipalib import api, errors, output
from ipalib import Bool, Str, StrEnum
from ipalib.plugable import Registry
@@ -10,6 +12,7 @@ from ipalib.plugins.baseldap import (
LDAPUpdate, LDAPRetrieve, LDAPAddMember, LDAPRemoveMember,
global_output_params, pkey_to_value)
from ipalib.plugins.hbacrule import is_all
+from ipalib.plugins.service import normalize_principal, split_any_principal
from ipalib import _, ngettext
from ipapython.dn import DN
@@ -50,6 +53,78 @@ EXAMPLES:
register = Registry()
+def _acl_make_request(principal_type, principal, ca_ref, profile_id):
+ """Construct HBAC request for the given principal, CA and profile"""
+ 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/'
+ elif principal_type == 'service':
+ req.user.name = normalize_principal(principal)
+ groups = []
+ if principal_type == 'user':
+ user_obj = api.Command.user_show(principal)['result']
+ 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']
+ groups = host_obj.get('memberof_hostgroup', [])
+ groups += host_obj.get('memberofindirect_hostgroup', [])
+ req.user.groups = sorted(set(groups))
+ return req
+
+
+def _acl_make_rule(principal_type, obj):
+ """Turn CA ACL object into HBAC rule.
+
+ ``principal_type``
+ String in {'user', 'host', 'service'}
+ """
+ rule = pyhbac.HbacRule(obj['cn'][0])
+ rule.enabled = obj['ipaenabledflag'][0]
+ rule.srchosts.category = {pyhbac.HBAC_CATEGORY_ALL}
+
+ # add CA(s)
+ # Hardcoded until caacl plugin arrives
+ rule.targethosts.category = {pyhbac.HBAC_CATEGORY_ALL}
+ #if 'cacategory' in obj and obj['cacategory'][0].lower() == 'all':
+ # rule.targethosts.category = {pyhbac.HBAC_CATEGORY_ALL}
+ #else:
+ # rule.targethosts.names = obj.get('ipacaaclcaref', [])
+
+ # add profiles
+ if 'profilecategory' in obj and obj['profilecategory'][0].lower() == 'all':
+ rule.services.category = {pyhbac.HBAC_CATEGORY_ALL}
+ else:
+ attr = 'memberprofile_certprofile'
+ rule.services.names = obj.get(attr, [])
+
+ # add principals and principal's groups
+ m = {'user': 'group', 'host': 'hostgroup', 'service': None}
+ category_attr = '{}category'.format(principal_type)
+ if category_attr in obj and obj[category_attr][0].lower() == 'all':
+ rule.users.category = {pyhbac.HBAC_CATEGORY_ALL}
+ else:
+ principal_attr = 'member{}_{}'.format(principal_type, principal_type)
+ rule.users.names = obj.get(principal_attr, [])
+ if m[principal_type] is not None:
+ group_attr = 'member{}_{}'.format(principal_type, m[principal_type])
+ rule.users.groups = obj.get(group_attr, [])
+
+ return rule
+
+
+def acl_evaluate(principal_type, principal, ca_ref, profile_id):
+ req = _acl_make_request(principal_type, principal, ca_ref, profile_id)
+ acls = api.Command.caacl_find()['result']
+ rules = [_acl_make_rule(principal_type, obj) for obj in acls]
+ return req.evaluate(rules) == pyhbac.HBAC_EVAL_ALLOW
+
+
@register()
class caacl(LDAPObject):
"""
diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py
index d122900175db41ba5af429fd47af6cac6533cb6f..1878e5ad5f80fa93e1a77b0a88711c1da0016681 100644
--- a/ipalib/plugins/cert.py
+++ b/ipalib/plugins/cert.py
@@ -33,6 +33,7 @@ from ipalib.plugins.virtual import *
from ipalib.plugins.baseldap import pkey_to_value
from ipalib.plugins.service import split_any_principal
from ipalib.plugins.certprofile import validate_profile_id
+import ipalib.plugins.caacl
import base64
import traceback
from ipalib.text import _
@@ -326,6 +327,22 @@ 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
+ )
+ )
+
bind_principal = split_any_principal(getattr(context, 'principal'))
bind_service, bind_name, bind_realm = bind_principal
--
2.1.0
More information about the Freeipa-devel
mailing list