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, during install and upgrade add a default CA ACL that permits
certificate issuance for all hosts and services using the profile
'caIPAserviceCert' on the top-level CA.

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

Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Fraser Tweedale 2015-05-25 08:39:07 -04:00 committed by Jan Cholasta
parent ae56ca422d
commit bc0c606885
16 changed files with 771 additions and 2 deletions

10
ACI.txt
View File

@ -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 = "hostcategory || ipacacategory || ipacertprofilecategory || ipamemberca || ipamembercertprofile || memberhost || memberservice || memberuser || 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 = "cn || createtimestamp || description || entryusn || hostcategory || ipacacategory || ipacertprofilecategory || ipaenabledflag || ipamemberca || ipamembercertprofile || ipauniqueid || member || memberhost || memberservice || memberuser || modifytimestamp || objectclass || 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

184
API.txt
View File

@ -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: StrEnum('ipacertprofilecategory', attribute=True, cli_name='profilecat', 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: 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: StrEnum('ipacertprofilecategory', attribute=True, autofill=False, cli_name='profilecat', 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: 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: StrEnum('ipacertprofilecategory', attribute=True, autofill=False, cli_name='profilecat', 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: 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')

View File

@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
IPA_API_VERSION_MINOR=127
# Last change: jcholast - add kra_is_enabled
IPA_API_VERSION_MINOR=128
# Last change: ftweedal - add caacl plugin

View File

@ -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 'ipaMemberCa' 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 'ipaMemberCertProfile' 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 'ipaCaCategory' 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 'ipaCertProfileCategory' 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 ( ipaCaCategory $ ipaCertProfileCategory $ userCategory $ hostCategory $ serviceCategory $ ipaMemberCa $ ipaMemberCertProfile $ memberService ) X-ORIGIN 'IPA v4.2' )

View File

@ -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 \

View File

@ -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

View File

@ -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
ipamembercertprofile: cn=caIPAserviceCert,cn=certprofiles,cn=ca,$SUFFIX
hostcategory: all
servicecategory: all

View File

@ -227,3 +227,23 @@ ObjectClass: top
ObjectClass: nsIndex
nsSystemIndex: false
nsIndexType: eq
dn: cn=ipaMemberCa,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
changetype: add
cn: ipaMemberCa
ObjectClass: top
ObjectClass: nsIndex
nsSystemIndex: false
nsIndexType: eq
nsIndexType: pres
nsIndexType: sub
dn: cn=ipaMemberCertProfile,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
changetype: add
cn: ipaMemberCertProfile
ObjectClass: top
ObjectClass: nsIndex
nsSystemIndex: false
nsIndexType: eq
nsIndexType: pres
nsIndexType: sub

View File

@ -191,3 +191,21 @@ default:nsSystemIndex: false
only:nsIndexType: eq
only:nsIndexType: pres
only:nsIndexType: sub
dn: cn=ipaMemberCa,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
default:cn: ipaMemberCa
default:ObjectClass: top
default:ObjectClass: nsIndex
default:nsSystemIndex: false
only:nsIndexType: eq
only:nsIndexType: pres
only:nsIndexType: sub
dn: cn=ipaMemberCertProfile,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
default:cn: ipaMemberCertProfile
default:ObjectClass: top
default:ObjectClass: nsIndex
default:nsSystemIndex: false
only:nsIndexType: eq
only:nsIndexType: pres
only:nsIndexType: sub

View File

@ -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: ipamemberca
add: referint-membership-attr: ipamembercertprofile

View File

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

View File

@ -34,6 +34,7 @@ app_DATA = \
40-automember.update \
40-certprofile.update \
40-otp.update \
41-caacl.update \
45-roles.update \
50-7_bit_check.update \
50-dogtag10-migration.update \

View File

@ -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'),

477
ipalib/plugins/caacl.py Normal file
View File

@ -0,0 +1,477 @@
#
# 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',
'ipacacategory', 'ipamemberca',
'ipacertprofilecategory', 'ipamembercertprofile',
'usercategory', 'memberuser',
'hostcategory', 'memberhost',
'servicecategory', 'memberservice',
]
uuid_attribute = 'ipauniqueid'
rdn_attribute = 'ipauniqueid'
attribute_members = {
'memberuser': ['user', 'group'],
'memberhost': ['host', 'hostgroup'],
'memberservice': ['service'],
'ipamembercertprofile': ['certprofile'],
}
managed_permissions = {
'System: Read CA ACLs': {
'replaces_global_anonymous_aci': True,
'ipapermbindruletype': 'all',
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
'cn', 'description', 'ipaenabledflag',
'ipacacategory', 'ipamemberca',
'ipacertprofilecategory', 'ipamembercertprofile',
'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': {
'ipacacategory', 'ipamemberca',
'ipacertprofilecategory', 'ipamembercertprofile',
'usercategory', 'memberuser',
'hostcategory', 'memberhost',
'servicecategory', 'memberservice'
},
'replaces': [
'(targetattr = "ipamemberca || ipamembercertprofile || memberuser || memberservice || memberhost || ipacacategory || ipacertprofilecategory || 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('ipacacategory?',
# cli_name='cacat',
# label=_('CA category'),
# doc=_('CA category the ACL applies to'),
# values=(u'all', ),
#),
StrEnum('ipacertprofilecategory?',
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('ipamemberca_subca?',
# label=_('CAs'),
# flags=['no_create', 'no_update', 'no_search'],
#),
Str('ipamembercertprofile_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, 'ipacacategory') and 'ipamemberca' in entry_attrs:
# raise errors.MutuallyExclusiveError(reason=_(
# "CA category cannot be set to 'all' "
# "while there are allowed CAs"))
if (is_all(options, 'ipacertprofilecategory')
and 'ipamembercertprofile' 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('ipamembercertprofile',
label=_('Failed profiles'),
),
# Commented until caacl plugin arrives
#Str('ipamemberca',
# label=_('Failed CAs'),
#),
)
@register()
class caacl_add_profile(LDAPAddMember):
__doc__ = _('Add profiles to a CA ACL.')
has_output_params = caacl_output_params
member_attributes = ['ipamembercertprofile']
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, 'ipacertprofilecategory'):
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 = ['ipamembercertprofile']
member_count_out = (_('%i profile removed.'), _('%i profiles removed.'))

View File

@ -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)

View File

@ -1254,6 +1254,30 @@ def update_mod_nss_protocol(http):
sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True)
def add_default_caacl(ca):
root_logger.info('[Add default CA ACL]')
if sysupgrade.get_upgrade_state('caacl', 'add_default_caacl'):
root_logger.info('Default CA ACL already added')
return
if ca.is_configured():
if not api.Backend.ldap2.isconnected():
try:
api.Backend.ldap2.connect(autobind=True)
except ipalib.errors.PublicError as e:
root_logger.error("Cannot connect to LDAP to add CA ACLs: %s", e)
return
if not api.Command.caacl_find()['result']:
api.Command.caacl_add(u'hosts_services_caIPAserviceCert',
hostcategory=u'all', usercategory=u'all')
api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert',
certprofile=(u'caIPAserviceCert',))
sysupgrade.set_upgrade_state('caacl', 'add_default_caacl', True)
def upgrade_configuration():
"""
Execute configuration upgrade of the IPA services
@ -1431,6 +1455,7 @@ def upgrade_configuration():
# itself require a restart.
#
ca_import_included_profiles(ca)
add_default_caacl(ca)
set_sssd_domain_option('ipa_server_mode', 'True')