On Mon, Jun 08, 2015 at 08:49:06AM +0200, Martin Kosek wrote: > On 06/08/2015 03:31 AM, Fraser Tweedale wrote: > > New patches attached. Comments inline. > > Thanks Fraser! > > ... > >> 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. > > AFAIR, yes. BTW, where does the "sub" index come from? It is quite an > expensive > index to use and I now cannot think of memberProfile search where you would > need a substring... > > Thanks, > Martin
Updated patch attached, which adds the indices. (Also rebased). There is a commit that seems to indicate that substring index is needed, so I have included substring indices in this patchset. Copied Honza in case he wants to comment. commit a10521a1dcf69960d6ce0bf5657180b709c297c0 Author: Jan Cholasta <jchol...@redhat.com> Date: Tue Jun 25 13:16:40 2013 +0000 Add missing substring indices for attributes managed by the referint plugin. The referint plugin does a substring search on these attributes each time an entry is deleted, which causes a noticable slowdown for large directories if the attributes are not indexed. https://fedorahosted.org/freeipa/ticket/3706 Cheers, Fraser
From 4ac84d1fd4baccecf6a73669943d6598ad604ad6 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@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/share/indices.ldif | 20 ++ install/updates/20-indices.update | 18 ++ 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 + 15 files changed, 745 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 9e3f223b7ac338840d7090299f9108e951ea920a..13268ce1abb6edcbe71d4585d77f57e46a8711f8 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 535b3e228a3500f2013ea793b19a97d9fbd05021..911470c2d83d81e6abee3e8e41496cf472a11d19 100644 --- a/VERSION +++ b/VERSION @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=126 -# Last change: edewata - added vault-archive and vault-retrieve +IPA_API_VERSION_MINOR=127 +# 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/share/indices.ldif b/install/share/indices.ldif index ad678e0b2123d961c957d3071ba48ff70bf27e7a..98aedca2d9c61c58e9d318cae909317a7d9d29a0 100644 --- a/install/share/indices.ldif +++ b/install/share/indices.ldif @@ -227,3 +227,23 @@ ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq + +dn: cn=memberCa,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config +changetype: add +cn: memberCa +ObjectClass: top +ObjectClass: nsIndex +nsSystemIndex: false +nsIndexType: eq +nsIndexType: pres +nsIndexType: sub + +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 diff --git a/install/updates/20-indices.update b/install/updates/20-indices.update index 880e73f3bb1b2a32c2fa40f65666cfd594cdc659..da9529272773995553ad2c056f2c5c03b847745b 100644 --- a/install/updates/20-indices.update +++ b/install/updates/20-indices.update @@ -191,3 +191,21 @@ default:nsSystemIndex: false only:nsIndexType: eq only:nsIndexType: pres only:nsIndexType: sub + +dn: cn=memberCa,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config +default:cn: memberCa +default:ObjectClass: top +default:ObjectClass: nsIndex +default:nsSystemIndex: false +only:nsIndexType: eq +only:nsIndexType: pres +only:nsIndexType: sub + +dn: cn=memberProfile,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config +default:cn: memberProfile +default:ObjectClass: top +default:ObjectClass: nsIndex +default:nsSystemIndex: false +only:nsIndexType: eq +only:nsIndexType: pres +only:nsIndexType: sub 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() + + +@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'], + ), + ) + + +@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 + + +@register() +class caacl_del(LDAPDelete): + __doc__ = _('Delete a CA ACL.') + + msg_summary = _('Deleted CA ACL "%(value)s"') + + +@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 + + +@register() +class caacl_find(LDAPSearch): + __doc__ = _('Search for CA ACLs.') + + msg_summary = ngettext( + '%(count)d CA ACL matched', '%(count)d CA ACLs matched', 0 + ) + + +@register() +class caacl_show(LDAPRetrieve): + __doc__ = _('Display the properties of a CA ACL.') + + +@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), + ) + + +@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), + ) + + +@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 + + +@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.')) + + +@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 + + +@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.')) + + +@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 + + +@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'), + #), +) + + +@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 + + +@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
From 3cf0f31fab9004fd1f16f8fdefa415d0d7aba0ad Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@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
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code